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?
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); } };
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)));
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.
- Zawijanie funkcji rzucania do standardowego interfejsu funkcjonalnego Java 8.
- łatwo określić różne zasady obsługi błędów
- podczas owijania metody, która zwraca wartość, istnieje ważne rozróżnienie pomiędzy określeniem wartości domyślnej lub ponownym określeniem wyjątku RuntimeException.
-
wrzucanie wersji Javy Funkcjonalne interfejsy 8
- podobne do odpowiedź fge
-
standardowe interfejsy do rzucania konkretnych WYJĄTKÓW
- które dotyczą troski Zoltána
Aby Włączyć duriana do swojego projektu, możesz:
- pobierz go z jcenter lub Maven central W
com.diffplug.durian:durian:3.3.0
- lub po prostu skopiuj wklej tylko dwie małe klasy do kodu:
Throwing.java
orazErrors.java
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
}
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;
}
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.
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);
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 { }
}
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")
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");
}
}
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());
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
).
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.
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)
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 .
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
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.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; });
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
Ładnie, prawda? Oczywiście zamiast Exception::printStackTrace można użyć loggera lub innej logiki obsługi.strStream.map(str -> amazingAPIs.myMethod(str, Exception::printStackTrace)) .filter(Optional::isPresent) .map(Optional::get).collect(toList());
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.
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
.
Po prostu unikaj funkcjonalnych interfejsów i używaj dobrej pętli for.
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.
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");
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)
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.
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());
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.
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: -
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();
}
}
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