Java 8 Lambda funkcja rzucająca wyjątek?

Wiem jak stworzyć odniesienie do metody, która ma parametr String i zwraca int, jest to:

Function<String, Integer>

Jednak to nie działa, jeśli funkcja rzuca wyjątek, powiedzmy, że jest zdefiniowany jako:

Integer myMethod(String s) throws IOException

Jak zdefiniowałbym to odniesienie?

Author: Lonely Neuron, 2013-08-13

23 answers

Musisz wykonać jedną z następujących czynności.

  • Jeśli jest to Twój kod, zdefiniuj własny interfejs funkcjonalny, który deklaruje zaznaczony wyjątek

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

    I użyj go

    void foo (CheckedFunction f) { ... }
    
  • W Przeciwnym Razie zawiń Integer myMethod(String s) w metodzie, która nie deklaruje wyjątku sprawdzonego:

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

    A następnie

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

    Lub

    Function<String, Integer> f =
        (String t) -> {
            try {
               return myMethod(t);
            }
            catch(IOException e) {
                throw new UncheckedIOException(e);
            }
        };
    
 312
Author: jason,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-28 09:44:05

Można rzeczywiście rozszerzyć Consumer (i Function itd.) z nowym interfejsem, który obsługuje wyjątki -- używając domyślnych metod Java 8 !

Rozważ ten interfejs (rozszerza 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;

}

Wtedy, na przykład, jeśli masz listę:

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

Jeśli chcesz go spożywać (np. z forEach) z kodem, który wyrzuca wyjątki, tradycyjnie skonfigurowałbyś blok try/catch:

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);

Ale z tym nowym interfejsem, można utworzyć go z wyrażenie lambda i kompilator nie będą narzekać:

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

Lub nawet po prostu rzucić go, aby być bardziej zwięzłe!:

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

Update: wygląda na to, że istnieje bardzo ładna część biblioteki narzędzi Durian o nazwie Errors , która może być użyta do rozwiązania tego problemu z większą elastycznością. Na przykład, w mojej implementacji powyżej wyraźnie zdefiniowałem politykę obsługi błędów (System.out... lub throw RuntimeException), podczas gdy błędy duriana pozwalają na stosowanie polityki w locie za pomocą dużego zestawu metod użytkowych. Dzięki za dzielenie się tym , @NedTwigg!.

Przykładowe użycie:

list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));
 158
Author: jlb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-30 10:25:01

Myślę, że Klasa durianaErrors łączy w sobie wiele zalet różnych sugestii powyżej.

Aby Włączyć duriana do swojego projektu, możesz:

 52
Author: Ned Twigg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:48

Nie jest to specyficzne dla Java 8. Próbujesz skompilować coś równoważnego:

interface I {
    void m();
}
class C implements I {
    public void m() throws Exception {} //can't compile
}
 23
Author: assylias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-12 23:36:50

Zastrzeżenie: nie używałem jeszcze Javy 8, tylko o niej czytałem.

Function<String, Integer> nie rzuca IOException, więc nie można umieścić w nim żadnego kodu throws IOException. Jeśli wywołujesz metodę, która oczekuje Function<String, Integer>, to lambda, którą przekazujesz tej metodzie, nie może rzucić IOException, kropka. Można też napisać lambda w ten sposób (myślę, że jest to składnia lambda, nie jestem pewien):

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

Lub, jeśli metoda, do której przekazujesz lambda jest tą, którą sam napisałeś, możesz zdefiniować nową funkcjonalność interfejs i użyj tego jako typ parametru zamiast Function<String, Integer>:

public interface FunctionThatThrowsIOException<I, O> {
    O apply(I input) throws IOException;
}
 11
Author: Adam R. Nelson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-12 23:30:57

Jeśli nie masz nic przeciwko użyciu 3rd party lib ( Vavr ) możesz napisać

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

Posiada również tzw. Monadę Try, która obsługuje błędy:

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

Proszę przeczytać więcej tutaj .

Zastrzeżenie: jestem twórcą Vavr.

 7
Author: Daniel Dietrich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-29 19:38:45

Możesz użyć unthrow wrapper

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

Lub

Function<String, Integer> func2 = s1 -> Unthrow.wrap((s2) -> myMethod(s2), s1);
 6
Author: SeregaLBN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-08 22:13:23

Możesz.

Rozszerzenie @marcg 's UtilException i dodanie generic <E extends Exception> tam, gdzie to konieczne: w ten sposób kompilator ponownie zmusi cię do dodania klauzul throw i wszystko będzie tak, jakbyś mógł natywnie rzucać wyjątki checked w strumieniach Javy 8.

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
Author: PaoloC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-03 10:35:10

Miałem problem z klasą.forName I Class.newInstance wewnątrz lambdy, więc po prostu zrobiłem:

public Object uncheckedNewInstanceForName (String name) {

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

Wewnątrz lambda, zamiast wywoływać klasę.forName ("myClass").newInstance() właśnie wywołałem uncheckedNewInstanceForName ("myClass")

 4
Author: Sergio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-17 12:21:18

Możesz jednak utworzyć własną interfejs funkcyjny, który rzuca jak poniżej..

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

Następnie zaimplementuj go używając lambda lub referencji, jak pokazano poniżej.

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");

 }

}
 4
Author: JohnnyO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-30 22:48:52

Innym rozwiązaniem używającym wrappera funkcji byłoby zwrócenie albo instancji wrappera wyniku, powiedzmy sukcesu, jeśli wszystko poszło dobrze, albo instancji, powiedzmy porażki.

Jakiś kod do wyjaśnienia rzeczy:

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;
    }
}

Prosty przypadek użycia:

List<Try<Integer>> result = Lists.newArrayList(1, 2, 3).stream().
    map(Try.<Integer, Integer>tryOf(i -> someMethodThrowingAnException(i))).
    collect(Collectors.toList());
 3
Author: yohan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-30 13:37:19

Ten problem również mnie niepokoi, dlatego stworzyłem Ten projekt .

Z nim możesz zrobić:

final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;

Istnieje totla 39 interfejsów zdefiniowanych przez JDK, które mają taki Throwing odpowiednik; są to wszystkie @FunctionalInterface używane w strumieniach (Baza Stream, ale także IntStream, LongStream i DoubleStream).

Kiedy każdy z nich rozszerza swój nie rzucający odpowiednik, można go również używać bezpośrednio w lambdach:]}
myStringStream.map(f) // <-- works

Domyślnym zachowaniem jest to, że kiedy twoja lambda rzuca wyjątek Sprawdzony, to ThrownByLambdaException jest wyrzucany z wyjątkiem sprawdzonym jako przyczyną. Możesz więc uchwycić to i uzyskać przyczynę.

Inne funkcje są również dostępne.

 3
Author: fge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-29 22:00:59

Możesz użyć ET do tego. ET jest małą biblioteką Java 8 do konwersji/tłumaczenia WYJĄTKÓW.

Z ET wygląda tak:

// 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 instancje są bezpieczne dla wątków i mogą być współdzielone przez wiele komponentów. Możesz skonfigurować bardziej szczegółowe reguły konwersji WYJĄTKÓW (np. FooCheckedException -> BarRuntimeException), jeśli chcesz. Jeśli inne reguły nie są dostępne, zaznaczone wyjątki są automatycznie konwertowane na RuntimeException.

(Zastrzeżenie: jestem autorem ET)

 3
Author: micha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-03 07:21:33

Idiom Sneaky throw umożliwia ominięcie CheckedException wyrażenia Lambda. Zawijanie {[2] } w RuntimeException nie jest dobre do ścisłej obsługi błędów.

Może być stosowany jako Consumer funkcja używana w kolekcji Java.

Oto prosta i ulepszona wersja jib ' s answer.

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);
        }
    }));
}

To otacza lambdę w rethrow. To sprawia, że CheckedException rethrow każdy Exception, który został wrzucony do Twojej lambdy.

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;
    }

}

Znajdź kompletny kod i testy jednostkowe tutaj .

 3
Author: myui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-01 14:29:01

Istnieje wiele świetnych odpowiedzi już zamieszczone tutaj. Próbuję rozwiązać problem z innej perspektywy. To tylko moje 2 centy, Proszę mnie poprawić, jeśli gdzieś się mylę.

Klauzula Throws w FunctionalInterface nie jest dobrym pomysłem

Myślę, że prawdopodobnie nie jest to dobry pomysł, aby wymuszać IOException z następujących powodów

  • To wygląda jak anty-wzór do Stream / Lambda. Cały pomysł jest taki, że rozmówca zdecyduje, jaki kod podać i jak obsłużyć wyjątek. W wielu scenariuszach IOException może nie mieć zastosowania dla klienta. Na przykład, jeśli klient pobiera wartość z pamięci podręcznej/pamięci zamiast wykonywać rzeczywiste operacje wejścia/Wyjścia.

  • Również obsługa wyjątków w strumieniach staje się naprawdę ohydna. Na przykład, oto mój kod będzie wyglądał tak, jeśli użyję twojego API

               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;
                });
    
    Brzydka prawda? Ponadto, jak wspomniałem w pierwszym punkcie, że metoda doSomeOperation może być rzucanie IOException (w zależności od implementacji klienta / rozmówcy), ale ze względu na klauzulę throws w metodzie FunctionalInterface, zawsze muszę napisać try-catch.

Co zrobić, jeśli naprawdę wiem, że to API rzuca IOException

  • Więc prawdopodobnie mylimy interfejs funkcyjny z typowymi interfejsami. Jeśli wiesz, że to API wyrzuci IOException, to najprawdopodobniej znasz też jakieś domyślne / abstrakcyjne również zachowanie. Myślę, że powinieneś zdefiniować interfejs i wdrożyć swoją bibliotekę (z domyślną / abstrakcyjną implementacją) w następujący sposób

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

    Ale problem try-catch nadal istnieje dla klienta. Jeśli używam twojego API w stream, nadal muszę obsługiwać IOException w blokach try-catch.

  • Podaj domyślne API przyjazne dla strumienia w następujący sposób

    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();
        }
    }
    

    Domyślna metoda przyjmuje jako argument obiekt consumer, który będzie odpowiedzialny za obsługę wyjątku. Teraz, z punktu widzenia Klienta, Kod będzie wyglądał tak

    strStream.map(str -> amazingAPIs.myMethod(str, Exception::printStackTrace))
                    .filter(Optional::isPresent)
                    .map(Optional::get).collect(toList());
    
    Ładnie, prawda? Oczywiście zamiast Exception::printStackTrace można użyć loggera lub innej logiki obsługi.
  • Można również wyeksponować metodę podobną do https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptionally-java.util.function.Function-. Co oznacza, że możesz wystawić inną metodę, która będzie zawierać wyjątek z poprzedniej metody sprawdzam. Wadą jest to, że teraz robisz swoje interfejsy API stanowe, co oznacza, że musisz obsługiwać thread-safety i które w końcu staną się hitem wydajności. To tylko opcja do rozważenia.

 2
Author: TriCore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-03 08:10:29

Utwórz niestandardowy typ zwracania, który będzie propagował zaznaczony wyjątek. Jest to alternatywa dla tworzenia nowego interfejsu, który odzwierciedla istniejący interfejs funkcjonalny z niewielką modyfikacją "wyjątku rzuca" w metodzie interfejsu funkcjonalnego.

Definicja

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);
        }
    }

}

Użycie

//  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();
Co się dzieje?

Dodanie "throws exception" do każdego funkcjonalnego interfejsu w JDK naruszyłby zasadę suchości w najbardziej ohydny sposób. Aby tego uniknąć, tworzony jest pojedynczy funkcjonalny interfejs, który rzuca zaznaczony wyjątek (CheckedValueSupplier). Będzie to jedyny funkcjonalny interfejs pozwalający na zaznaczone wyjątki. Wszystkie inne Interfejsy funkcjonalne wykorzystają CheckedValueSupplier, aby zawinąć dowolny kod, który rzuca zaznaczony wyjątek.

Klasa CheckedValue będzie przechowywać wynik wykonania dowolnej logiki, która rzuca zaznaczony wyjątek. Zapobiega to rozprzestrzenianiu się zaznaczony wyjątek do momentu, w którym kod próbuje uzyskać dostęp do wartości, którą zawiera instancja CheckedValue.

Problemy z tym podejściem.

  • rzucamy teraz "wyjątek" skutecznie ukrywając konkretny typ pierwotnie rzucony.
  • nie jesteśmy świadomi, że wyjątek wystąpił, dopóki nie zostanie wywołany CheckedValue#get().

Consumer et al

Niektóre funkcjonalne interfejsy (Consumer na przykład) muszą być obsługiwane w inny sposób, ponieważ nie zapewniają wartość zwracana.

Funkcja zamiast konsumenta

Jedną z metod jest użycie funkcji zamiast konsumenta, która ma zastosowanie podczas obsługi strumieni.

    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

Eskalacja

Alternatywnie, zawsze możesz eskalować do RuntimeException. Istnieją inne odpowiedzi, które obejmują eskalację sprawdzonego wyjątku z Consumer.

Nie konsumuj.

Po prostu unikaj funkcjonalnych interfejsów i używaj dobrej pętli for.

 2
Author: justin.hughey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-30 15:06:28

Domyślnie, funkcja Java 8 nie pozwala na rzucanie wyjątków i jak sugerowano w wielu odpowiedziach, można to osiągnąć na wiele sposobów, jednym ze sposobów jest:

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

Zdefiniuj jako:

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

I dodać throws lub try/catch ten sam wyjątek w metodzie wywołującej.

 2
Author: Arpit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-13 15:44:18

Jeśli nie masz nic przeciwko użyciu biblioteki innej firmy, z cyclops-react , biblioteką, do której się przyczyniam, możesz użyć FluentFunctions API do napisania

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

OfChecked pobiera sprawdzoną funkcję Joo i zwraca odwołanie z powrotem do Standardowej (niezaznaczonej) JDK Javy.util.funkcja.Funkcja.

Alternatywnie możesz kontynuować pracę z przechwyconą funkcją za pośrednictwem interfejsu API FluentFunctions!

Na przykład, aby wykonać metodę, powtarzając ją do 5 razy i rejestrując jego status możesz napisać

  FluentFunctions.ofChecked(this::myMethod)
                 .log(s->log.debug(s),e->log.error(e,e.getMessage())
                 .try(5,1000)
                 .apply("my param");
 1
Author: John McClean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-24 15:56:57

To, co robię, to umożliwienie użytkownikowi podania wartości, której naprawdę chce w przypadku wyjątku . Więc mam coś takiego

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;
}

A to może być wywołane TAK:

defaultIfThrows(child -> child.getID(), null)
 0
Author: mmounirou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-30 12:37:50

Kilka z oferowanych rozwiązań używa ogólnego argumentu E, aby przekazać typ wyjątku, który zostanie wyrzucony.

Pójdź o krok dalej, i zamiast przechodzić w rodzaju wyjątku, przejść w Konsumenta typu wyjątku, jak w...

Consumer<E extends Exception>

Możesz utworzyć kilka wariantów Consumer<Exception> do ponownego użycia, które pokryłyby typowe potrzeby obsługi wyjątków Twojej aplikacji.

 0
Author: Rodney P. Barbati,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-12 16:07:34

Zrobię coś ogólnego:

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);

        }
    }
}

Użycie:

 Lambda.handle(() -> method());
 0
Author: ahll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-21 11:23:06

Użyj Jool Library lub powiedz jOOλ library z JOOQ. Nie tylko zapewnia niezaznaczone interfejsy obsługiwane przez wyjątki, ale także zapewnia klasę Seq z wieloma użytecznymi metodami.

Zawiera również funkcjonalne Interfejsy z maksymalnie 16 parametrami. Ponadto zapewnia klasę krotki, która jest używana w różnych scenariuszach.

Jool Git Link

W szczególności w wyszukiwaniu biblioteki dla org.jooq.lambda.fi.util.function pakietu. Zawiera wszystkie interfejsy z Java-8 z Checked prepended. Zobacz poniżej Referencja: -

Tutaj wpisz opis obrazka

 0
Author: Vinay Prajapati,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-12 09:22:59
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();
    }
}
 -7
Author: Franky Knuckels,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-25 19:37:54