İstisna atan Java 8 Lambda işlevi?


470

Nasıl bir Stringparametre ve bir döndüren bir yönteme başvuru oluşturmak biliyorum int, bu:

Function<String, Integer>

Ancak, işlev bir istisna atarsa ​​bu çalışmaz, diyelim ki:

Integer myMethod(String s) throws IOException

Bu referansı nasıl tanımlayabilirim?





4
Tüm çözüm, Çalışma Zamanı istisnalarını atmak gibi, bunun iyi bir çözüm olmadığına inanıyorum. döngüler için eski java kullanmak çok daha iyi
Nazeel

5
Jool kütüphanesi ne olacak ? Kontrolsüz paket
chaiyachaiya

Yanıtlar:


403

Aşağıdakilerden birini yapmanız gerekir.

  • Kodunuzsa, kontrol edilen istisnayı bildiren kendi işlevsel arayüzünüzü tanımlayın:

    @FunctionalInterface
    public interface CheckedFunction<T, R> {
       R apply(T t) throws IOException;
    }

    ve kullanın:

    void foo (CheckedFunction f) { ... }
  • Aksi takdirde, Integer myMethod(String s)işaretli bir istisna bildirmeyen bir yöntem girin:

    public Integer myWrappedMethod(String s) {
        try {
            return myMethod(s);
        }
        catch(IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    ve sonra:

    Function<String, Integer> f = (String t) -> myWrappedMethod(t);

    veya:

    Function<String, Integer> f =
        (String t) -> {
            try {
               return myMethod(t);
            }
            catch(IOException e) {
                throw new UncheckedIOException(e);
            }
        };

7
Aslında genişletebilir Consumerveya Functionvarsayılan yöntemleri kullanıyorsanız - aşağıdaki cevabımı görebilirsiniz.
jlb


6
Küçük optimizasyon: Bunun yerine (String t) -> myWrappedMethod(t)yöntem referansı this::myWrappedMethodda kullanılabilir.
Clashsoft

8
Bunu yapmanın daha genel bir yolu, işaretli işlevi şu şekilde tanımlamaktır @FunctionalInterface genel arabirimi CheckedFunction <T, R, E İstisna genişletir> {R uygula (T t) E atar; } Bu şekilde işlevin hangi istisnayı attığını tanımlayabilir ve arabirimi herhangi bir kod için yeniden kullanabilirsiniz.
Martin Odhelius

3
Vay. Java düşündüğümden daha kötü
user275801

194

Java 8'in varsayılan yöntemlerini kullanarak istisnaları ele alan yeni bir arayüzle aslında genişletebilirsiniz Consumer(ve Functionvb.) !

Bu arayüzü düşünün (genişletir Consumer):

@FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {

    @Override
    default void accept(final T elem) {
        try {
            acceptThrows(elem);
        } catch (final Exception e) {
            // Implement your own exception handling logic here..
            // For example:
            System.out.println("handling an exception...");
            // Or ...
            throw new RuntimeException(e);
        }
    }

    void acceptThrows(T elem) throws Exception;

}

Ardından, örneğin, bir listeniz varsa:

final List<String> list = Arrays.asList("A", "B", "C");

forEachİstisnalar atan bir kodla (örneğin ile ) tüketmek isterseniz, geleneksel olarak bir dene / yakala bloğu ayarlamış olursunuz:

final Consumer<String> consumer = aps -> {
    try {
        // maybe some other code here...
        throw new Exception("asdas");
    } catch (final Exception ex) {
        System.out.println("handling an exception...");
    }
};
list.forEach(consumer);

Ancak bu yeni arayüzle, lambda ifadesiyle başlatabilirsiniz ve derleyici şikayet etmeyecektir:

final ThrowingConsumer<String> throwingConsumer = aps -> {
    // maybe some other code here...
    throw new Exception("asdas");
};
list.forEach(throwingConsumer);

Ya da sadece daha özlü olmak için yayınlayın !:

list.forEach((ThrowingConsumer<String>) aps -> {
    // maybe some other code here...
    throw new Exception("asda");
});

Güncelleme : Durian'ın çok daha fazla esneklikle bu sorunu çözmek için kullanılabilecek Hatalar adlı çok güzel bir yardımcı program kütüphanesi parçası olduğu anlaşılıyor . Örneğin, yukarıdaki uygulamamda hata işleme politikasını ( System.out...veya throw RuntimeException) açıkça tanımladım , oysa Durian'ın Hataları büyük bir yardımcı program yöntemi aracılığıyla anında bir politika uygulamanıza izin veriyor. İçin teşekkürler paylaşarak , @NedTwigg !.

Örnek kullanım:

list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));

14
Yani bir takım arayüzlere (Fonksiyon, Tüketici, Tedarikçi, ...) ve hataların ele alınmasına yönelik bir dizi politikaya (Throwing, System.out.println, ...) sahipsiniz. Bence bir yol var kolay "vb ThrowingConsumer, ThrowingFunction," yapıştırmak kopyalamak zorunda kalmadan, fonksiyonun her türlü ile herhangi bir ilkeyi kullanmaya yapmak.
Ned Twigg

1
bir süre sonra ... Denetlenmeyen istisnalar kullanmaya ve herhangi bir ek işlevsel arayüz veya yeni kütüphane kullanmaya karar verdim -> kolay yol, daha az yazım, daha hızlı teslimat, değil mi?
aliopi

1
İşte sinsi fırlatma deyimini kullanan geliştirilmiş bir versiyon . RuntimeException özelliğinin CheckException içinde açılmasına gerek yoktur.
myui

62

Durian'ın Errorssınıfının yukarıdaki çeşitli önerilerin profesyonellerinin birçoğunu birleştirdiğini düşünüyorum .

Durian'ı projenize dahil etmek için aşağıdakilerden birini yapabilirsiniz:


Veya akışlar doğal hata işlemeye ihtiyaç duyduğundan RxJava'yı kullanabilirsiniz ve boru hattınızda bir istisna atan bir şey varsa, muhtemelen gözlemlenebilir bir akış olması için iyi bir şans vardır. Bu, Java 8'i bir kütüphanenin alt tüketicileri için de zorlamaz.
Adam Gent

2
Durian'ın Haziran 2016'dan bu yana yeni bir sürümü olmadığını lütfen unutmayın . Bir şov tıpası değil, akılda tutulması gereken bir şey.
Istvan Devai

9
Durian sürdürücü burada. Ne kırıldı? Bir kullanıcı bir hata veya önemli bir eksik özellik bulursa, hızlıca bir hata düzeltmesi yaparız. Kütüphane basit, bu yüzden herhangi bir hata raporumuz yoktu, bu yüzden herhangi bir hata düzeltmesi yayınlamamız gerekmedi.
Ned Twigg

28

Bu, Java 8'e özgü değildir. Aşağıdakilere eşdeğer bir şey derlemeye çalışıyorsunuz:

interface I {
    void m();
}
class C implements I {
    public void m() throws Exception {} //can't compile
}

15
Soru "Bu referansı nasıl tanımlarım?" . Bu aslında soruyu cevaplamıyor; sadece sorunun ne olduğunu açıklar.
Dawood ibn Kareem

13

Feragatname: Henüz Java 8 kullanmadım, sadece okudum.

Function<String, Integer>atmaz IOException, bu yüzden içine herhangi bir kod koyamazsınız throws IOException. Bekleyen bir yöntem Function<String, Integer>arıyorsanız, o yönteme ilettiğiniz lambda atılamaz IOException, nokta. Ya da böyle bir lambda yazabilirsiniz (sanırım bu lambda sözdizimi, emin değilim):

(String s) -> {
    try {
        return myMethod(s);
    } catch (IOException ex) {
        throw new RuntimeException(ex);
        // (Or do something else with it...)
    }
}

Veya, lambda'yı geçtiğiniz yöntem kendiniz yazdığınız yöntemse, yeni bir fonksiyonel arayüz tanımlayabilir ve bunu parametre tipi olarak kullanabilirsiniz Function<String, Integer>:

public interface FunctionThatThrowsIOException<I, O> {
    O apply(I input) throws IOException;
}

Arayüzünüzden önce @FunctionalInterface ek açıklaması ekleyin, ancak o zaman lambdas için kullanılabilir.
Gangnus

13
@Gangnus: @FunctionalInterfaceaçıklama, lambdalar için kullanılabilir olması için gerekli değildir. Yine de akıl sağlığı kontrolü için önerilir.
Tanmay Patil

9

Üçüncü taraf bir lib ( Vavr ) kullanmak sakıncası yoksa,

CheckedFunction1<String, Integer> f = this::myMethod;

Aynı zamanda hataları işleyen Try monad denir:

Try(() -> f.apply("test")) // results in a Success(Integer) or Failure(Throwable)
        .map(i -> ...) // only executed on Success
        ...

Lütfen buradan daha fazlasını okuyun .

Feragatname: Ben Vavr'ın yaratıcısıyım.


7

Açılmamış sarıcı kullanabilirsiniz

Function<String, Integer> func1 = s -> Unthrow.wrap(() -> myMethod(s));

veya

Function<String, Integer> func2 = s1 -> Unthrow.wrap((s2) -> myMethod(s2), s1);

6

Ancak aşağıdaki gibi atanan kendi Fonksiyonel Arayüzünüzü oluşturabilirsiniz.

@FunctionalInterface
public interface UseInstance<T, X extends Throwable> {
  void accept(T instance) throws X;
}

daha sonra Lambdas veya aşağıda gösterilen referansları kullanarak uygulayın.

import java.io.FileWriter;
import java.io.IOException;

//lambda expressions and the execute around method (EAM) pattern to
//manage resources

public class FileWriterEAM  {
  private final FileWriter writer;

  private FileWriterEAM(final String fileName) throws IOException {
    writer = new FileWriter(fileName);
  }
  private void close() throws IOException {
    System.out.println("close called automatically...");
    writer.close();
  }
  public void writeStuff(final String message) throws IOException {
    writer.write(message);
  }
  //...

  public static void use(final String fileName, final UseInstance<FileWriterEAM, IOException> block) throws IOException {

    final FileWriterEAM writerEAM = new FileWriterEAM(fileName);    
    try {
      block.accept(writerEAM);
    } finally {
      writerEAM.close();
    }
  }

  public static void main(final String[] args) throws IOException {

    FileWriterEAM.use("eam.txt", writerEAM -> writerEAM.writeStuff("sweet"));

    FileWriterEAM.use("eam2.txt", writerEAM -> {
        writerEAM.writeStuff("how");
        writerEAM.writeStuff("sweet");      
      });

    FileWriterEAM.use("eam3.txt", FileWriterEAM::writeIt);     

  }


 void writeIt() throws IOException{
     this.writeStuff("How ");
     this.writeStuff("sweet ");
     this.writeStuff("it is");

 }

}

6

Yapabilirsin.

@Marcg 'lerin genişletilmesi UtilExceptionve <E extends Exception>gerektiğinde jenerik eklenmesi : bu şekilde, derleyici sizi tekrar atma cümleleri eklemeye zorlar ve her şeyi java 8'in akışlarına yerel olarak kontrol edilmiş istisnalar atabilirsiniz.

public final class LambdaExceptionUtil {

    @FunctionalInterface
    public interface Function_WithExceptions<T, R, E extends Exception> {
        R apply(T t) throws E;
    }

    /**
     * .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName))
     */
    public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E  {
        return t -> {
            try {
                return function.apply(t);
            } catch (Exception exception) {
                throwActualException(exception);
                return null;
            }
        };
    }

    @SuppressWarnings("unchecked")
    private static <E extends Exception> void throwActualException(Exception exception) throws E {
        throw (E) exception;
    }

}

public class LambdaExceptionUtilTest {

    @Test
    public void testFunction() throws MyTestException {
        List<Integer> sizes = Stream.of("ciao", "hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
        assertEquals(2, sizes.size());
        assertEquals(4, sizes.get(0).intValue());
        assertEquals(5, sizes.get(1).intValue());
    }

    private Integer transform(String value) throws MyTestException {
        if(value==null) {
            throw new MyTestException();
        }
        return value.length();
    }

    private static class MyTestException extends Exception { }
}

5

Bir lambda içinde Class.forName ve Class.newInstance ile bu sorunu vardı, bu yüzden sadece yaptım:

public Object uncheckedNewInstanceForName (String name) {

    try {
        return Class.forName(name).newInstance();
    }
    catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

Lambda içinde Class.forName ("myClass") çağırmak yerine. NewInstance () Az önce uncheckedNewInstanceForName ("myClass") olarak adlandırdım


4

İşlev sarıcı kullanan başka bir çözüm, sonucunuzun bir sarıcısının bir örneğini döndürmektir, mesela Başarı, her şey yolunda giderse, ya da bir örneği, Başarısızlık diyelim.

Bazı şeyleri açıklığa kavuşturmak için bazı kodlar:

public interface ThrowableFunction<A, B> {
    B apply(A a) throws Exception;
}

public abstract class Try<A> {

    public static boolean isSuccess(Try tryy) {
        return tryy instanceof Success;
    }

    public static <A, B> Function<A, Try<B>> tryOf(ThrowableFunction<A, B> function) {
        return a -> {
            try {
                B result = function.apply(a);
                return new Success<B>(result);
            } catch (Exception e) {
                return new Failure<>(e);
            }
        };
    }

    public abstract boolean isSuccess();

    public boolean isError() {
        return !isSuccess();
    }

    public abstract A getResult();

    public abstract Exception getError();
}

public class Success<A> extends Try<A> {

    private final A result;

    public Success(A result) {
        this.result = result;
    }

    @Override
    public boolean isSuccess() {
        return true;
    }

    @Override
    public A getResult() {
        return result;
    }

    @Override
    public Exception getError() {
        return new UnsupportedOperationException();
    }

    @Override
    public boolean equals(Object that) {
        if(!(that instanceof Success)) {
            return false;
        }
        return Objects.equal(result, ((Success) that).getResult());
    }
}

public class Failure<A> extends Try<A> {

    private final Exception exception;

    public Failure(Exception exception) {
        this.exception = exception;
    }

    @Override
    public boolean isSuccess() {
        return false;
    }

    @Override
    public A getResult() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Exception getError() {
        return exception;
    }
}

Basit bir kullanım örneği:

List<Try<Integer>> result = Lists.newArrayList(1, 2, 3).stream().
    map(Try.<Integer, Integer>tryOf(i -> someMethodThrowingAnException(i))).
    collect(Collectors.toList());

4

Bu sorun da beni rahatsız ediyor; bu yüzden bu projeyi yarattım .

Bununla birlikte şunları yapabilirsiniz:

final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;

JDK tarafından tanımlanan böyle bir Throwingeşdeğere sahip 39 arayüzden oluşan bir totla vardır ; Bu hepsi @FunctionalInterfaceakımları kullanılan ler (baz Stream, aynı zamanda IntStream, LongStreamve DoubleStream).

Ve her biri fırlatmayan muadillerini uzattıkça, onları doğrudan lambdalarda da kullanabilirsiniz:

myStringStream.map(f) // <-- works

Varsayılan davranış, fırlatma lambda'nız işaretli bir istisna attığında ThrownByLambdaException, nedeni olarak işaretli istisna ile a atılmasıdır. Bu nedenle bunu yakalayabilir ve sebebini elde edebilirsiniz.

Diğer özellikler de mevcuttur.


Fikri gerçekten çok beğendim, sadece burada önerildiği gibi genel olarak kullanılabilir sarf malzemelerini yapmanı dilerim: javaspecialists.eu/archive/Issue221.html , örneğin: @FunctionalInterface public interface SupplierWithCE<T, X extends Exception> { T get() throws X; }- bu şekilde kullanıcının yakalaması gerekmez Throwable, bunun yerine belirli kontrol edilen istisna.
Zoltán

@ Zoltán her seferinde istisna bildirmek için bir acı olurdu; Ayrıca, her zaman sadece .doApply () yerine, .apply () kullanabilir ve yakalayabilirsiniz ThrownByLambdaException, bir neden olarak orijinal istisnanız olacaktır (veya kullanabilirsiniz rethrow(...).as(MyRuntimeException.class))
fge

Bence bunun bir yolu var .
Ned Twigg

@NedTwigg Bunu uzun zaman önce de çözdüm; Şimdi Throwing.runnable()ve diğerlerini her zaman zincirleme yetenekleriyle kullanabilirim
fge

Zincirleme işlevi çok havalı! Benim yorumum, ThrowingRunnable'ın genel istisnası olup olmayacağı ile ilgiliydi. Zoltan kütüphanenizin genel bir parametre olarak argümana sahip olup olamayacağını sordu ve bunun bir acı olacağını söylediniz. Bağlantım, istisnaların bir acı olmadan jenerik olmasını sağlamanın bir yolunu gösteren bazı kod satırlarıydı. Yanlış okumadığım sürece, kitaplığınızdaki istisnalar genel değildir (bu makul bir tasarım seçimidir, çünkü onları genel hale getirerek fazla fayda elde edemezsiniz).
Ned Twigg

4

Burada zaten yayınlanmış çok sayıda harika yanıt var. Sorunu farklı bir bakış açısıyla çözmeye çalışmak. Bu sadece benim 2 sent, bir yerde yanılıyorsanız lütfen beni düzeltin.

FunctionalInterface içindeki atar yan tümcesi iyi bir fikir değil

Bence bu, aşağıdaki nedenlerden dolayı IOException'ı zorlamak için iyi bir fikir değil.

  • Bu bana Stream / Lambda'ya karşı bir anti-desen gibi geliyor. Bütün fikir, arayan kişinin hangi kodu vereceğine ve istisnanın nasıl işleneceğine karar vereceğidir. Birçok senaryoda, IOException istemci için geçerli olmayabilir. Örneğin, istemci gerçek G / Ç gerçekleştirmek yerine önbellekten / bellekten değer alıyorsa.

  • Ayrıca, akışlarda işlenen istisnalar gerçekten iğrenç hale gelir. Örneğin, API'nızı kullanırsam kodum şöyle görünecek

               acceptMyMethod(s -> {
                    try {
                        Integer i = doSomeOperation(s);
                        return i;
                    } catch (IOException e) {
                        // try catch block because of throws clause
                        // in functional method, even though doSomeOperation
                        // might not be throwing any exception at all.
                        e.printStackTrace();
                    }
                    return null;
                });

    Çirkin değil mi? Dahası, ilk noktamda belirttiğim gibi, doSomeOperation yönteminin IOException'ı (istemcinin / arayanın uygulanmasına bağlı olarak) fırlatabileceği veya vermeyebileceği, ancak FunctionalInterface yönteminizdeki throws cümlesi nedeniyle, her zaman deneyin-catch.

Bu API'nın gerçekten IOException atarsa ​​ne yapmalıyım

  • O zaman muhtemelen FunctionalInterface'i tipik arabirimlerle karıştırıyoruz. Bu API'nın IOException kuracağını biliyorsanız, büyük olasılıkla bazı varsayılan / soyut davranışları da biliyorsunuzdur. Bir arayüz tanımlamanız ve kütüphanenizi (varsayılan / soyut uygulama ile) aşağıdaki gibi dağıtmanız gerektiğini düşünüyorum

    public interface MyAmazingAPI {
        Integer myMethod(String s) throws IOException;
    }

    Ancak, istemci için try-catch sorunu hala var. API'nızı akışta kullanırsam, yine de iğrenç try-catch bloğunda IOException'ı kullanmam gerekir.

  • Aşağıdaki gibi varsayılan akış dostu bir API sağlayın

    public interface MyAmazingAPI {
        Integer myMethod(String s) throws IOException;
    
        default Optional<Integer> myMethod(String s, Consumer<? super Exception> exceptionConsumer) {
            try {
                return Optional.ofNullable(this.myMethod(s));
            } catch (Exception e) {
                if (exceptionConsumer != null) {
                    exceptionConsumer.accept(e);
                } else {
                    e.printStackTrace();
                }
            }
    
            return Optional.empty();
        }
    }

    Varsayılan yöntem, tüketici nesnesini istisnayı işlemekten sorumlu olacak argüman olarak alır. Şimdi, müşterinin bakış açısından, kod şöyle görünecek

    strStream.map(str -> amazingAPIs.myMethod(str, Exception::printStackTrace))
                    .filter(Optional::isPresent)
                    .map(Optional::get).collect(toList());

    Güzel değil mi? Elbette Exception :: printStackTrace yerine kaydedici veya başka bir işlem mantığı kullanılabilir.

  • Ayrıca https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptionally-java.util.function.Function- benzeri bir yöntemi de açığa çıkarabilirsiniz . Önceki yöntem çağrısının istisnasını içeren başka bir yöntemi açığa çıkarabileceğiniz anlamına gelir. Dezavantajı, şimdi API'larınızı durum bilgisi haline getirmiş olmanızdır; Sadece düşünmek için bir seçenek.


İşaretli İstisnayı kontrol edilmemiş bir İstisna'ya dönüştürmenin veya İstisnayı yutmanın iyi bir fikir olmadığını kabul ediyorum, çünkü Streambir İstisna'nın hangi elemanını oluşturduğunu bilmenin bir yolu yoktur . Bu nedenle, bir istisna işleyicisi olması ve geçerli olmayan sonuçları filtreleme fikrini seviyorum. MyAmazingAPI'nızın etkili bir şekilde bir olduğuna dikkat edin FunctionalInterface(bu nedenle @FunctionalInterface ek açıklamasını ekleyebilirsiniz). Ayrıca kullanmak yerine varsayılan bir değere sahip olabilirsiniz Optional.empty().
Julien Kronegg

4

Sinsi atış deyimiCheckedException Lambda ifadesinin atlanmasını sağlar . Bir tamamlayan CheckedExceptionbir de RuntimeExceptionsıkı hata işleme için iyi değil.

ConsumerJava koleksiyonunda kullanılan bir işlev olarak kullanılabilir.

İşte pergel cevabının basit ve geliştirilmiş bir versiyonu .

import static Throwing.rethrow;

@Test
public void testRethrow() {
    thrown.expect(IOException.class);
    thrown.expectMessage("i=3");

    Arrays.asList(1, 2, 3).forEach(rethrow(e -> {
        int i = e.intValue();
        if (i == 3) {
            throw new IOException("i=" + i);
        }
    }));
}

Bu lambda'yı bir rıhtımda sarar . CheckedExceptionLambda'nıza Exceptionatılan her şeyi yeniden yapar .

public final class Throwing {
    private Throwing() {}

    @Nonnull
    public static <T> Consumer<T> rethrow(@Nonnull final ThrowingConsumer<T> consumer) {
        return consumer;
    }

    /**
     * The compiler sees the signature with the throws T inferred to a RuntimeException type, so it
     * allows the unchecked exception to propagate.
     * 
     * http://www.baeldung.com/java-sneaky-throws
     */
    @SuppressWarnings("unchecked")
    @Nonnull
    public static <E extends Throwable> void sneakyThrow(@Nonnull Throwable ex) throws E {
        throw (E) ex;
    }

}

Kod ve birim testlerinin tamamını burada bulabilirsiniz .


3

Bunun için ET'yi kullanabilirsiniz . ET, istisna dönüştürme / çeviri için küçük bir Java 8 kütüphanesidir.

ET ile şöyle görünür:

// Do this once
ExceptionTranslator et = ET.newConfiguration().done();

...

// if your method returns something
Function<String, Integer> f = (t) -> et.withReturningTranslation(() -> myMethod(t));

// if your method returns nothing
Consumer<String> c = (t) -> et.withTranslation(() -> myMethod(t));

ExceptionTranslatorörnekler iş parçacığı için güvenlidir ve birden çok bileşen tarafından paylaşılabilir. İsterseniz daha spesifik istisna dönüşüm kuralları (ör. FooCheckedException -> BarRuntimeException) Yapılandırabilirsiniz . Başka kural yoksa, işaretli istisnalar otomatik olarak dönüştürülür RuntimeException.

(Feragatname: ET'nin yazarıyım)


2
Görünüşe göre bu kütüphanenin yazarı sizsiniz. Göre SO kuralları , sen gerekir yanıtlarınıza ilişkinizi açıklamaktadır. Lütfen bu kütüphaneyi yazdığınız cevaba açıkça ekleyin (ET ile ilgili diğer cevaplar için de geçerlidir).
Tagir Valeev

2
Merhaba Tagir, ipucu için teşekkürler. Cevabı güncelledim.
micha

2

Yaptığım şey, istisna durumunda kullanıcının istediği değeri vermesine izin vermektir. Yani şöyle bir şey var

public static <T, R> Function<? super T, ? extends R> defaultIfThrows(FunctionThatThrows<? super T, ? extends R> delegate, R defaultValue) {
    return x -> {
        try {
            return delegate.apply(x);
        } catch (Throwable throwable) {
            return defaultValue;
        }
    };
}

@FunctionalInterface
public interface FunctionThatThrows<T, R> {
    R apply(T t) throws Throwable;
}

Ve bu daha sonra şöyle çağrılabilir:

defaultIfThrows(child -> child.getID(), null)

1
Bu , "varsayılan değer" stratejisi (yanıtınızda olduğu gibi) ile varsayılan değerin gerekli olmadığı "yeniden çalışma zamanı özel durumu" ifadesini yeniden ayıran bu fikrin bir uzantısıdır.
Ned Twigg

2

Katkıda bulunduğum bir kütüphane olan cyclops -tepki ile üçüncü taraf bir kitaplık kullanmak sakıncası yoksa , yazmak için FluentFunctions API'sını kullanabilirsiniz.

 Function<String, Integer> standardFn = FluentFunctions.ofChecked(this::myMethod);

ofChecked bir jOOλ CheckedFunction alır ve yumuşatılmış referansı standart (denetlenmemiş) JDK java.util.function.Function öğesine geri döndürür.

Alternatif olarak yakalanan işlevle FluentFunctions api!

Örneğin, yönteminizi yürütmek, en fazla 5 kez yeniden denemek ve durumunu günlüğe yazmak için yazabilirsiniz

  FluentFunctions.ofChecked(this::myMethod)
                 .log(s->log.debug(s),e->log.error(e,e.getMessage())
                 .try(5,1000)
                 .apply("my param");

2

Varsayılan olarak, Java 8 İşlevi istisna atmaya izin vermez ve birden fazla yanıtta önerildiği gibi, bunu başarmanın birçok yolu vardır, bir yol:

@FunctionalInterface
public interface FunctionWithException<T, R, E extends Exception> {
    R apply(T t) throws E;
}

Olarak tanımlamak:

private FunctionWithException<String, Integer, IOException> myMethod = (str) -> {
    if ("abc".equals(str)) {
        throw new IOException();
    }
  return 1;
};

Ve ekleyin throwsveya try/catchaynı istisna arayan yöntemi.


2

İşaretli özel durumu çoğaltacak özel bir dönüş türü oluşturun. Bu, fonksiyonel arabirimin yönteminde bir "istisna atar" ufak bir değişiklikle mevcut işlevsel arabirimi yansıtan yeni bir arabirim oluşturmaya bir alternatiftir.

Tanım

CheckedValueSupplier

public static interface CheckedValueSupplier<V> {
    public V get () throws Exception;
}

CheckedValue

public class CheckedValue<V> {
    private final V v;
    private final Optional<Exception> opt;

    public Value (V v) {
        this.v = v;
    }

    public Value (Exception e) {
        this.opt = Optional.of(e);
    }

    public V get () throws Exception {
        if (opt.isPresent()) {
            throw opt.get();
        }
        return v;
    }

    public Optional<Exception> getException () {
        return opt;
    }

    public static <T> CheckedValue<T> returns (T t) {
        return new CheckedValue<T>(t);
    }

    public static <T> CheckedValue<T> rethrows (Exception e) {
        return new CheckedValue<T>(e);
    }

    public static <V> CheckedValue<V> from (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            return Result.rethrows(e);
        }
    }

    public static <V> CheckedValue<V> escalates (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

kullanım

//  Don't use this pattern with FileReader, it's meant to be an
//  example.  FileReader is a Closeable resource and as such should
//  be managed in a try-with-resources block or in another safe
//  manner that will make sure it is closed properly.

//  This will not compile as the FileReader constructor throws
//  an IOException.
    Function<String, FileReader> sToFr =
        (fn) -> new FileReader(Paths.get(fn).toFile());

// Alternative, this will compile.
    Function<String, CheckedValue<FileReader>> sToFr = (fn) -> {
        return CheckedValue.from (
            () -> new FileReader(Paths.get("/home/" + f).toFile()));
    };

// Single record usage
    // The call to get() will propagate the checked exception if it exists.
    FileReader readMe = pToFr.apply("/home/README").get();


// List of records usage
    List<String> paths = ...; //a list of paths to files
    Collection<CheckedValue<FileReader>> frs =
        paths.stream().map(pToFr).collect(Collectors.toList());

// Find out if creation of a file reader failed.
    boolean anyErrors = frs.stream()
        .filter(f -> f.getException().isPresent())
        .findAny().isPresent();

Neler oluyor?

İşaretli bir istisna atan tek bir işlevsel arabirim oluşturulur ( CheckedValueSupplier). Bu, kontrol edilen istisnalara izin veren tek işlevsel arayüz olacaktır. Diğer tüm işlevsel arabirimler, CheckedValueSupplierdenetlenen bir özel durum oluşturan herhangi bir kodu sarmak için kullanılır.

CheckedValueSınıf bir kontrol istisna atar herhangi bir mantık yürütme sonucunu tutacaktır. Bu, kodun bir örneğinin CheckedValueiçerdiği değere erişmeye çalıştığı noktaya kadar işaretli bir istisnanın yayılmasını önler .

Bu yaklaşımla ilgili sorunlar.

  • Şimdi atılan spesifik türü etkili bir şekilde gizleyerek "İstisna" yı atıyoruz.
  • Şu ana kadar istisna oluştuğunun farkında değiliz CheckedValue#get().

Tüketici ve ark.

Bazı fonksiyonel arayüzler (Consumer örneğin) bir dönüş değeri sağlamadığından farklı bir şekilde ele alınmalıdır.

Tüketici yerine işlev

Bir yaklaşım, akışları ele alırken geçerli olan tüketici yerine bir işlev kullanmaktır.

    List<String> lst = Lists.newArrayList();
// won't compile
lst.stream().forEach(e -> throwyMethod(e));
// compiles
lst.stream()
    .map(e -> CheckedValueSupplier.from(
        () -> {throwyMethod(e); return e;}))
    .filter(v -> v.getException().isPresent()); //this example may not actually run due to lazy stream behavior

kızıştırmak

Alternatif olarak, her zaman a'ya yükseltebilirsiniz RuntimeException. İşaretli bir kural dışı durumun a Consumer.

Tüketim.

Fonksiyonel arayüzleri bir arada kullanmaktan kaçının ve döngü için iyi bir ole tarzı kullanın.


2

unchecked()Birden fazla kullanım durumunu işleyen adlı aşırı yüklenmiş bir yardımcı işlev kullanıyorum.


BAZI ÖRNEK KULLANIMLAR

unchecked(() -> new File("hello.txt").createNewFile());

boolean fileWasCreated = unchecked(() -> new File("hello.txt").createNewFile());

myFiles.forEach(unchecked(file -> new File(file.path).createNewFile()));

DESTEKLEYEN YARDIMCI PROGRAMLAR

public class UncheckedUtils {

    @FunctionalInterface
    public interface ThrowingConsumer<T> {
        void accept(T t) throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingSupplier<T> {
        T get() throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingRunnable {
        void run() throws Exception;
    }

    public static <T> Consumer<T> unchecked(
            ThrowingConsumer<T> throwingConsumer
    ) {
        return i -> {
            try {
                throwingConsumer.accept(i);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        };
    }

    public static <T> T unchecked(
            ThrowingSupplier<T> throwingSupplier
    ) {
        try {
            return throwingSupplier.get();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static void unchecked(
            ThrowingRunnable throwing
    ) {
        try {
            throwing.run();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

0

Sunulan çözümlerin birçoğu, atılan istisna türünü iletmek için genel bir E argümanı kullanır.

Bu adımı bir adım daha ileri götürün ve istisna türünü geçmek yerine, istisna türü bir Tüketici'yi olduğu gibi ...

Consumer<E extends Exception>

Consumer<Exception>Uygulamanızın ortak istisna işleme ihtiyaçlarını karşılayacak birkaç yeniden kullanılabilir varyasyon oluşturabilirsiniz .


0

Genel bir şey yapacağım:

public interface Lambda {

    @FunctionalInterface
    public interface CheckedFunction<T> {

        T get() throws Exception;
    }

    public static <T> T handle(CheckedFunction<T> supplier) {
        try {
            return supplier.get();
        } catch (Exception exception) {
            throw new RuntimeException(exception);

        }
    }
}

kullanımı:

 Lambda.handle(() -> method());

0

Kullanım Jool Libraryveya söylemek jOOλ librarydanJOOQ . Yalnızca denetlenmeyen özel durum işleme arabirimleri sağlamakla kalmaz, aynı zamanda Seq sınıfına birçok yararlı yöntem sağlar.

Ayrıca, 16 parametreye kadar Fonksiyonel Arayüzler içerir. Ayrıca, farklı senaryolarda kullanılan Tuple sınıfı sağlar.

Jool Git Bağlantısı

Özellikle org.jooq.lambda.fi.util.functionpaket için kütüphane aramasında . Java-8'in tüm arayüzlerini Checked ekli olarak içerir. Referans için aşağıya bakın: -

resim açıklamasını buraya girin


0

Herhangi bir Java İstisnasını herhangi bir yere yakalamadan veya sarmalamadanRuntimeException atmak için genel bir sihire sahip küçük bir lib'in yazarıyım .

Kullanımı: unchecked(() -> methodThrowingCheckedException())

public class UncheckedExceptions {

    /**
     * throws {@code exception} as unchecked exception, without wrapping exception.
     *
     * @return will never return anything, return type is set to {@code exception} only to be able to write <code>throw unchecked(exception)</code>
     * @throws T {@code exception} as unchecked exception
     */
    @SuppressWarnings("unchecked")
    public static <T extends Throwable> T unchecked(Exception exception) throws T {
        throw (T) exception;
    }


    @FunctionalInterface
    public interface UncheckedFunction<R> {
        R call() throws Exception;
    }

    /**
     * Executes given function,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @return result of function
     * @see #unchecked(Exception)
     */
    public static <R> R unchecked(UncheckedFunction<R> function) {
        try {
            return function.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }


    @FunctionalInterface
    public interface UncheckedMethod {
        void call() throws Exception;
    }

    /**
     * Executes given method,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @see #unchecked(Exception)
     */
    public static void unchecked(UncheckedMethod method) {
        try {
            method.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }
}

Kaynak: https://github.com/qoomon/unchecked-exceptions-java


-7
public void frankTest() {
    int pageId= -1;

    List<Book> users= null;
    try {
        //Does Not Compile:  Object page=DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> new Portal(rw.getInt("id"), "", users.parallelStream().filter(uu -> uu.getVbid() == rw.getString("user_id")).findFirst().get(), rw.getString("name")));

        //Compiles:
        Object page= DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> { 
            try {
                final Book bk= users.stream().filter(bp -> { 
                    String name= null;
                    try {
                        name = rw.getString("name");
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    return bp.getTitle().equals(name); 
                }).limit(1).collect(Collectors.toList()).get(0);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return new Portal(rw.getInt("id"), "", users.get(0), rw.getString("name")); 
        } );
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

3
Çalışmanıza yorum yapmak ister misiniz? Yalnızca kod yanıtları çok kullanışlı değildir.
Phantômaxx

@Franky sunumunuzu 4 yerine 4 boşluk kullanarak düzeltebilirsiniz <code>/<code>:)
AdrieanKhisbe
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.