Wiem, jak utworzyć odwołanie do metody, która ma String
parametr i zwraca int
:
Function<String, Integer>
Nie działa to jednak, jeśli funkcja zgłasza wyjątek, powiedzmy, że jest zdefiniowana jako:
Integer myMethod(String s) throws IOException
Jak zdefiniowałbym to odniesienie?
Odpowiedzi:
Musisz wykonać jedną z następujących czynności.
Jeśli to twój kod, zdefiniuj własny interfejs funkcjonalny, który deklaruje sprawdzony wyjątek:
i użyj go:
W przeciwnym razie zawiń
Integer myMethod(String s)
metodę, która nie deklaruje sprawdzonego wyjątku:i wtedy:
lub:
źródło
Consumer
lubFunction
jeśli używasz metod domyślnych - zobacz moją odpowiedź poniżej.(String t) -> myWrappedMethod(t)
odwołania do metodythis::myWrappedMethod
.Możesz faktycznie rozszerzyć
Consumer
(iFunction
itp.) Za pomocą nowego interfejsu, który obsługuje wyjątki - używając domyślnych metod Java 8 !Rozważ ten interfejs (rozszerza
Consumer
):Na przykład, jeśli masz listę:
Jeśli chcesz go skonsumować (np. Z
forEach
) kodem, który generuje wyjątki, tradycyjnie skonfigurowałbyś blok try / catch:Ale dzięki temu nowemu interfejsowi możesz utworzyć instancję z wyrażeniem lambda, a kompilator nie będzie narzekał:
Lub nawet po prostu rzuć to bardziej zwięźle !:
Aktualizacja : Wygląda na to, że to bardzo miły część biblioteki użyteczność Durian zwane błędy , które mogą być wykorzystane, aby rozwiązać ten problem z elastycznością wiele więcej. Na przykład w powyższej implementacji wyraźnie zdefiniowałem zasady obsługi błędów (
System.out...
lubthrow RuntimeException
), podczas gdy błędy Duriana pozwalają na stosowanie zasad w locie za pomocą dużego zestawu metod narzędziowych. Dzięki za udostępnienie , @NedTwigg !.Przykładowe użycie:
źródło
Myślę, że klasa Duriana
Errors
łączy wiele zalet różnych sugestii powyżej.Aby włączyć Durian do swojego projektu, możesz:
com.diffplug.durian:durian:3.3.0
Throwing.java
iErrors.java
źródło
Nie dotyczy to Java 8. Próbujesz skompilować coś równoważnego do:
źródło
Oświadczenie: Nie korzystałem jeszcze z Java 8, tylko o tym poczytałem.
Function<String, Integer>
nie rzucaIOException
, więc nie możesz w to wstawić żadnego koduthrows IOException
. Jeśli wywołujesz metodę, która oczekuje aFunction<String, Integer>
, to lambda, którą przekazujesz do tej metody, nie może rzucaćIOException
kropką. Możesz albo napisać lambda w ten sposób (myślę, że to jest składnia lambda, nie jestem pewien):Lub, jeśli metoda, którą przekazujesz lambda, jest tą, którą sam napisałeś, możesz zdefiniować nowy interfejs funkcjonalny i użyć go jako typu parametru zamiast
Function<String, Integer>
:źródło
@FunctionalInterface
adnotacja nie jest wymagana, aby można ją było wykorzystać w lambdas. Jest to jednak zalecane do kontroli poczytalności.Jeśli nie masz nic przeciwko korzystaniu z biblioteki innej firmy ( Vavr ), możesz napisać
Ma również tak zwaną Try monad, która obsługuje błędy:
Przeczytaj więcej tutaj .
Oświadczenie: Jestem twórcą Vavr.
źródło
Możesz użyć narzędzia „Unhrow wrapper”
lub
źródło
Możesz jednak stworzyć swój własny interfejs FunctionalInterface, który będzie wyrzucany jak poniżej.
następnie zaimplementuj go za pomocą Lambdas lub odnośników, jak pokazano poniżej.
źródło
Możesz.
Rozszerzanie @marcg
UtilException
i dodawanie ogólnych<E extends Exception>
tam, gdzie to konieczne: w ten sposób kompilator zmusi cię ponownie do dodania klauzul rzucania i wszystko będzie tak, jakbyś mógł natywnie sprawdzać wyjątki natywnie w strumieniach Java 8.źródło
Miałem ten problem z Class.forName i Class.newInstance wewnątrz lambda, więc po prostu:
Wewnątrz lambdy zamiast wywoływać Class.forName („myClass”). NewInstance () Właśnie wywołałem uncheckedNewInstanceForName („myClass”)
źródło
Innym rozwiązaniem wykorzystującym opakowanie funkcji byłoby zwrócenie albo wystąpienia opakowania wyniku, powiedzmy Sukces, jeśli wszystko poszło dobrze, albo wystąpienia, powiedzmy Niepowodzenie.
Niektóre kody do wyjaśnienia rzeczy:
Prosty przypadek użycia:
źródło
Ten problem również mnie niepokoi; dlatego stworzyłem ten projekt .
Dzięki niemu możesz:
Istnieje łącznie 39 interfejsów zdefiniowanych przez JDK, które mają taki
Throwing
odpowiednik; te są@FunctionalInterface
y stosowane w strumieniach (podkładStream
, ale takżeIntStream
,LongStream
iDoubleStream
).A ponieważ każdy z nich rozszerza swój nie rzucający odpowiednik, możesz bezpośrednio używać go również w lambdach:
Domyślne zachowanie polega na tym, że gdy twoja lambda rzuca sprawdzony wyjątek,
ThrownByLambdaException
generowany jest a, którego przyczyną jest sprawdzony wyjątek. Możesz więc to uchwycić i uzyskać przyczynę.Dostępne są również inne funkcje.
źródło
@FunctionalInterface public interface SupplierWithCE<T, X extends Exception> { T get() throws X; }
- w ten sposób użytkownik nie musi wychwytywaćThrowable
, ale zamiast tego sprawdził wyjątek.ThrownByLambdaException
, będziesz mieć oryginalny wyjątek jako przyczynę (lub możesz użyćrethrow(...).as(MyRuntimeException.class)
)Throwing.runnable()
innych i zawsze z możliwościami łączeniaIstnieje już wiele świetnych odpowiedzi tutaj. Próbuję rozwiązać problem z innej perspektywy. To tylko moje 2 centy, proszę mnie poprawić, jeśli się mylę.
Klauzula Throws w FunctionalInterface nie jest dobrym pomysłem
Myślę, że prawdopodobnie nie jest dobrym pomysłem egzekwowanie wyjątków IOException z następujących powodów
Wygląda mi to na anty-wzór dla Stream / Lambda. Cały pomysł polega na tym, że osoba dzwoniąca decyduje, jaki kod podać i jak obsłużyć wyjątek. W wielu scenariuszach wyjątek IOEx może nie mieć zastosowania do klienta. Na przykład, jeśli klient otrzymuje wartość z pamięci podręcznej / pamięci zamiast wykonywać rzeczywiste operacje we / wy.
Ponadto obsługa wyjątków w strumieniach staje się naprawdę ohydna. Na przykład, oto mój kod będzie wyglądał, jeśli użyję twojego API
Brzydka prawda? Ponadto, jak wspomniałem w pierwszym punkcie, że metoda doSomeOperation może generować wyjątek IOException (w zależności od implementacji klienta / wywołującego), ale z powodu klauzuli throws w metodzie FunctionalInterface zawsze muszę napisać próbuj złapać.
Co mam zrobić, jeśli naprawdę wiem, że ten interfejs API zgłasza wyjątek IOException
Prawdopodobnie mylimy interfejs Functional z typowymi interfejsami. Jeśli wiesz, że ten interfejs API wyrzuci wyjątek IOException, najprawdopodobniej znasz również pewne domyślne / abstrakcyjne zachowanie. Myślę, że powinieneś zdefiniować interfejs i wdrożyć bibliotekę (z domyślną / abstrakcyjną implementacją) w następujący sposób
Jednak nadal występuje problem z try-catch dla klienta. Jeśli używam interfejsu API w strumieniu, nadal muszę obsługiwać wyjątek IOExou w ohydnym bloku try-catch.
Podaj domyślny przyjazny interfejs API w następujący sposób
Domyślna metoda przyjmuje obiekt konsumenta jako argument, który będzie odpowiedzialny za obsługę wyjątku. Teraz, z punktu widzenia klienta, kod będzie wyglądał następująco
Fajnie prawda? Oczywiście zamiast Exception :: printStackTrace można zastosować logger lub inną logikę obsługi.
Możesz także udostępnić metodę podobną do https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptionally-java.util.function.Function- . Oznacza to, że możesz udostępnić inną metodę, która będzie zawierać wyjątek od poprzedniego wywołania metody. Wadą jest to, że teraz ustawiasz interfejsy API w stan, co oznacza, że musisz zająć się bezpieczeństwem wątków i które ostatecznie stanie się hitem wydajności. Tylko opcja do rozważenia.
źródło
Stream
zgłoszonego wyjątku. Dlatego podoba mi się pomysł obsługi wyjątku i filtrowania niepoprawnych wyników. Zauważ, że MyAmazingAPI jest w rzeczywistościFunctionalInterface
(dlatego możesz dodać adnotację @FunctionalInterface). Możesz także mieć wartość domyślną zamiast używaćOptional.empty()
.Podstępny idiom rzutu umożliwia ominięcie
CheckedException
wyrażenia Lambda. ZawijanieCheckedException
wRuntimeException
nie jest dobre dla ścisłej obsługi błędów.Może być używany jako
Consumer
funkcja używana w kolekcji Java.Oto prosta i ulepszona wersja odpowiedzi wysięgnika .
To właśnie Wrapps lambda w rethrow . Powoduje to
CheckedException
rzucenie każdego,Exception
co zostało wrzucone do twojej lambda.Znajdź pełny kod i testy jednostkowe tutaj .
źródło
Możesz do tego użyć ET . ET to mała biblioteka Java 8 do konwersji / tłumaczenia wyjątków.
Z ET wygląda to tak:
ExceptionTranslator
instancje są bezpieczne dla wątków i mogą być współużytkowane przez wiele komponentów. Możesz skonfigurować bardziej szczegółowe reguły konwersji wyjątków (np.FooCheckedException -> BarRuntimeException
), Jeśli chcesz. Jeśli żadne inne reguły nie są dostępne, zaznaczone wyjątki są automatycznie konwertowane naRuntimeException
.(Uwaga: Jestem autorem ET)
źródło
To, co robię, polega na umożliwieniu użytkownikowi podania wartości, której faktycznie chce w przypadku wyjątku. Więc mam coś takiego
Można to nazwać tak:
źródło
Jeśli nie masz nic przeciwko korzystaniu z biblioteki strony trzeciej, z biblioteką cyclops- reag , biblioteką, w której pracuję, możesz użyć FluentFunctions interfejsu API do pisania
Funkcja ofChecked przyjmuje funkcję CheckedFunkcja jOOλ i zwraca zmiękczoną referencję do standardowej (niezaznaczonej) funkcji JDK java.util.function.Funkcja.
Alternatywnie możesz kontynuować pracę z przechwyconą funkcją za pomocą interfejsu FluentFunctions!
Na przykład, aby wykonać metodę, ponów ją do 5 razy i zapisz jej status, który możesz napisać
źródło
Domyślnie funkcja Java 8 nie zezwala na zgłaszanie wyjątku, a jak sugerowano w wielu odpowiedziach, istnieje wiele sposobów jego osiągnięcia, jednym ze sposobów jest:
Zdefiniuj jako:
I dodaj
throws
lubtry/catch
ten sam wyjątek w metodzie dzwoniącego.źródło
Utwórz niestandardowy typ zwrotu, który będzie propagował sprawdzony wyjątek. Jest to alternatywa dla tworzenia nowego interfejsu, który odzwierciedla istniejący interfejs funkcjonalny z niewielką modyfikacją „zgłasza wyjątek” w metodzie interfejsu funkcjonalnego.
Definicja
CheckedValueSupplier
CheckedValue
Stosowanie
Co się dzieje?
Tworzony jest pojedynczy interfejs funkcjonalny, który zgłasza sprawdzony wyjątek (
CheckedValueSupplier
). Będzie to jedyny funkcjonalny interfejs, który pozwala na sprawdzanie wyjątków. Wszystkie inne interfejsy funkcjonalne wykorzystająCheckedValueSupplier
do zawinięcia dowolnego kodu, który zgłasza sprawdzony wyjątek.CheckedValue
Klasa odbędzie wyniku wykonywania jakiejkolwiek logiki, która rzuca sprawdzonej wyjątek. Zapobiega to propagacji sprawdzonego wyjątku do momentu, w którym kod będzie próbował uzyskać dostęp do wartości, którą zawiera instancjaCheckedValue
.Problemy z tym podejściem.
CheckedValue#get()
zostanie wywołany.Consumer i in
Niektóre interfejsy funkcjonalne (
Consumer
na przykład) muszą być obsługiwane w inny sposób, ponieważ nie zapewniają wartości zwracanej.Funkcja zamiast konsumenta
Jednym z podejść jest użycie funkcji zamiast konsumenta, co ma zastosowanie podczas obsługi strumieni.
Zwiększać
Alternatywnie, zawsze możesz eskalować do
RuntimeException
. Istnieją inne odpowiedzi, które obejmują eskalację sprawdzonego wyjątku z poziomuConsumer
.Nie spożywaj
Po prostu unikaj funkcjonalnych interfejsów i używaj dobrze zaprojektowanej pętli for.
źródło
Używam przeciążonej funkcji narzędzia o nazwie,
unchecked()
która obsługuje wiele przypadków użycia.NIEKTÓRE PRZYKŁADOWE ZASTOSOWANIA
NARZĘDZIA WSPIERAJĄCE
źródło
Niektóre z oferowanych rozwiązań wykorzystują ogólny argument E, aby przekazać typ wyjątku, który zostanie zgłoszony.
Przejdź o krok dalej i zamiast wprowadzać typ wyjątku, przekaż konsumentowi tego rodzaju wyjątek, jak w ...
Możesz utworzyć kilka wariantów wielokrotnego użytku,
Consumer<Exception>
które pokryłyby typowe potrzeby aplikacji w zakresie obsługi wyjątków.źródło
Zrobię coś ogólnego:
stosowanie:
źródło
Użyj
Jool Library
lub powiedzjOOλ library
zJOOQ
. Zapewnia nie tylko niesprawdzone interfejsy obsługiwane w wyjątkach, ale także zapewnia klasie Seq wiele przydatnych metod.Zawiera także interfejsy funkcjonalne z maksymalnie 16 parametrami. Zapewnia także klasę Tuple, która jest używana w różnych scenariuszach.
Jool Git Link
W szczególności w poszukiwaniu biblioteki dla
org.jooq.lambda.fi.util.function
pakietu. Zawiera wszystkie interfejsy z Java-8 z zaznaczonym sprawdzeniem. Zobacz poniżej w celach informacyjnych: -źródło
Jestem autorem niewielkiej biblioteki lib z pewną ogólną magią, aby wrzucić dowolne wyjątki Java w dowolne miejsce bez potrzeby ich łapania lub pakowania
RuntimeException
.Stosowanie:
unchecked(() -> methodThrowingCheckedException())
źródło: https://github.com/qoomon/unchecked-exceptions-java
źródło
źródło
<code>/<code>
:)