Ich weiß , wie eine Referenz auf ein Verfahren zu schaffen , das eine hat String
Parameter und gibt ein int
, das sind :
Function<String, Integer>
Dies funktioniert jedoch nicht, wenn die Funktion eine Ausnahme auslöst, beispielsweise wie folgt definiert:
Integer myMethod(String s) throws IOException
Wie würde ich diese Referenz definieren?
Antworten:
Sie müssen einen der folgenden Schritte ausführen.
Wenn es Ihr Code ist, definieren Sie Ihre eigene Funktionsschnittstelle, die die aktivierte Ausnahme deklariert:
und benutze es:
Andernfalls schließen Sie
Integer myMethod(String s)
eine Methode ein, die keine aktivierte Ausnahme deklariert:und dann:
oder:
quelle
Consumer
oderFunction
wenn Sie Standardmethoden verwenden - siehe meine Antwort unten.(String t) -> myWrappedMethod(t)
die Methodenreferenzthis::myWrappedMethod
verwendet werden.Sie können tatsächlich
Consumer
(undFunction
usw.) mit einer neuen Schnittstelle erweitern, die Ausnahmen behandelt - unter Verwendung der Standardmethoden von Java 8 !Betrachten Sie diese Schnittstelle (erweitert
Consumer
):Dann zum Beispiel, wenn Sie eine Liste haben:
Wenn Sie es (z. B. mit
forEach
) mit einem Code verwenden möchten , der Ausnahmen auslöst, hätten Sie traditionell einen try / catch-Block eingerichtet:Mit dieser neuen Schnittstelle können Sie sie jedoch mit einem Lambda-Ausdruck instanziieren, und der Compiler wird sich nicht beschweren:
Oder wirf es einfach, um es prägnanter zu machen!:
Update : Anscheinend gibt es in Durian einen sehr schönen Teil der Utility-Bibliothek namens Errors, mit dem dieses Problem viel flexibler gelöst werden kann. Zum Beispiel habe ich in meiner obigen Implementierung die Fehlerbehandlungsrichtlinie (
System.out...
oder explizit definiert)throw RuntimeException
) , während Sie mit Durians Fehlern eine Richtlinie im laufenden Betrieb über eine große Reihe von Dienstprogrammmethoden anwenden können. Vielen Dank für das Teilen , @NedTwigg!.Beispielnutzung:
quelle
Ich denke, Durians
Errors
Klasse kombiniert viele der Profis der verschiedenen obigen Vorschläge.Um Durian in Ihr Projekt aufzunehmen, können Sie entweder:
com.diffplug.durian:durian:3.3.0
Throwing.java
undErrors.java
quelle
Dies ist nicht spezifisch für Java 8. Sie versuchen, etwas zu kompilieren, das Folgendes entspricht:
quelle
Haftungsausschluss: Ich habe Java 8 noch nicht verwendet, sondern nur darüber gelesen.
Function<String, Integer>
wirft nichtIOException
, also kannst du keinen Code hineinsteckenthrows IOException
. Wenn Sie eine Methode aufrufen, die a erwartetFunction<String, Integer>
, kann das Lambda, das Sie an diese Methode übergeben, keinenIOException
Punkt auslösen . Sie können entweder ein Lambda wie dieses schreiben (ich denke, dies ist die Lambda-Syntax, nicht sicher):Wenn Sie das Lambda an eine Methode übergeben, die Sie selbst geschrieben haben, können Sie eine neue Funktionsschnittstelle definieren und diese als Parametertyp verwenden, anstatt
Function<String, Integer>
:quelle
@FunctionalInterface
Anmerkung ist nicht erforderlich, damit sie für Lambdas verwendet werden kann. Es wird jedoch zur Überprüfung der geistigen Gesundheit empfohlen.Wenn es Ihnen nichts ausmacht, eine Drittanbieter- Bibliothek ( Vavr ) zu verwenden, können Sie schreiben
Es hat auch die sogenannte Try-Monade, die Fehler behandelt:
Bitte lesen Sie hier mehr .
Haftungsausschluss: Ich bin der Schöpfer von Vavr.
quelle
Sie können Unthrow Wrapper verwenden
oder
quelle
Sie können jedoch Ihr eigenes FunctionalInterface erstellen, das wie folgt ausgelöst wird.
Implementieren Sie es dann mit Lambdas oder Referenzen, wie unten gezeigt.
quelle
Du kannst.
Erweitern von @marcg 's
UtilException
und Hinzufügen von Generika, falls<E extends Exception>
erforderlich: Auf diese Weise zwingt Sie der Compiler erneut, Throw-Klauseln hinzuzufügen, und alles ist so, als könnten Sie geprüfte Ausnahmen nativ in die Streams von Java 8 werfen.quelle
Ich hatte dieses Problem mit Class.forName und Class.newInstance in einem Lambda, also habe ich einfach Folgendes getan:
Anstatt Class.forName ("myClass"). NewInstance () aufzurufen, habe ich im Lambda einfach uncheckedNewInstanceForName ("myClass") aufgerufen.
quelle
Eine andere Lösung, die einen Funktions-Wrapper verwendet, besteht darin, entweder eine Instanz eines Wrappers Ihres Ergebnisses zurückzugeben, z. B. Erfolg, wenn alles gut gelaufen ist, oder eine Instanz von beispielsweise Fehler.
Einige Codes zur Verdeutlichung:
Ein einfacher Anwendungsfall:
quelle
Dieses Problem hat mich auch gestört; Deshalb habe ich dieses Projekt erstellt .
Damit können Sie tun:
Es gibt insgesamt 39 vom JDK definierte Schnittstellen, die ein solches
Throwing
Äquivalent haben. das ist alles@FunctionalInterface
s in Strömen (die Basis verwendet ,Stream
sondern auchIntStream
,LongStream
undDoubleStream
).Und da jeder von ihnen sein nicht werfendes Gegenstück erweitert, können Sie sie auch direkt in Lambdas verwenden:
Das Standardverhalten ist, dass, wenn Ihr Lambda eine aktivierte Ausnahme auslöst, a
ThrownByLambdaException
mit der aktivierten Ausnahme als Ursache ausgelöst wird. Sie können das also erfassen und die Ursache ermitteln.Weitere Funktionen sind ebenfalls verfügbar.
quelle
@FunctionalInterface public interface SupplierWithCE<T, X extends Exception> { T get() throws X; }
- auf diese Weise muss der Benutzer nicht fangenThrowable
, sondern stattdessen die speziell aktivierte Ausnahme.ThrownByLambdaException
, Sie haben die ursprüngliche Ausnahme als Ursache (oder Sie können verwendenrethrow(...).as(MyRuntimeException.class)
)Throwing.runnable()
und andere verwenden, immer mit VerkettungsfunktionenEs gibt bereits viele großartige Antworten, die hier veröffentlicht wurden. Ich versuche nur, das Problem mit einer anderen Perspektive zu lösen. Es sind nur meine 2 Cent, bitte korrigieren Sie mich, wenn ich irgendwo falsch liege.
Die Throws-Klausel in FunctionalInterface ist keine gute Idee
Ich denke, dies ist aus folgenden Gründen wahrscheinlich keine gute Idee, um IOException-Würfe durchzusetzen
Das sieht für mich wie ein Anti-Pattern für Stream / Lambda aus. Die ganze Idee ist, dass der Anrufer entscheidet, welcher Code bereitgestellt werden soll und wie die Ausnahme behandelt werden soll. In vielen Szenarien ist die IOException möglicherweise nicht für den Client anwendbar. Zum Beispiel, wenn der Client einen Wert aus dem Cache / Speicher erhält, anstatt die eigentliche E / A auszuführen.
Außerdem wird die Behandlung von Ausnahmen in Streams wirklich abscheulich. Hier sieht mein Code beispielsweise so aus, als würde ich Ihre API verwenden
Hässlich, nicht wahr? Wie ich in meinem ersten Punkt erwähnt habe, löst die doSomeOperation-Methode möglicherweise eine IOException aus oder nicht (abhängig von der Implementierung des Clients / Aufrufers), aber aufgrund der throw-Klausel in Ihrer FunctionalInterface-Methode muss ich immer die schreiben versuchen zu fangen.
Was mache ich, wenn ich wirklich weiß, dass diese API eine IOException auslöst?
Dann verwechseln wir FunctionalInterface wahrscheinlich mit typischen Interfaces. Wenn Sie wissen, dass diese API eine IOException auslöst, kennen Sie höchstwahrscheinlich auch ein standardmäßiges / abstraktes Verhalten. Ich denke, Sie sollten eine Schnittstelle definieren und Ihre Bibliothek (mit Standard- / abstrakter Implementierung) wie folgt bereitstellen
Das Try-Catch-Problem besteht jedoch weiterhin für den Client. Wenn ich Ihre API im Stream verwende, muss ich die IOException immer noch in einem abscheulichen Try-Catch-Block behandeln.
Stellen Sie eine standardmäßige streamfreundliche API wie folgt bereit
Die Standardmethode verwendet das Consumer-Objekt als Argument, das für die Behandlung der Ausnahme verantwortlich ist. Aus Sicht des Kunden sieht der Code nun so aus
Schön, oder? Natürlich könnte anstelle von Exception :: printStackTrace ein Logger oder eine andere Verarbeitungslogik verwendet werden.
Sie können auch eine ähnliche Methode wie https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptionally-java.util.function.Function- verfügbar machen . Dies bedeutet, dass Sie eine andere Methode verfügbar machen können, die die Ausnahme vom vorherigen Methodenaufruf enthält. Der Nachteil ist, dass Sie Ihre APIs jetzt statusbehaftet machen, was bedeutet, dass Sie sich um die Thread-Sicherheit kümmern müssen und dass dies letztendlich zu einem Leistungseinbruch wird. Nur eine Option zu prüfen.
quelle
Stream
Ausnahme ausgelöst hat. Daher gefällt mir die Idee, einen Ausnahmebehandler zu haben und die ungültigen Ergebnisse zu filtern. Beachten Sie, dass Ihre MyAmazingAPI effektiv eine istFunctionalInterface
(daher können Sie die Annotation @FunctionalInterface hinzufügen). Sie können auch einen Standardwert anstelle von verwendenOptional.empty()
.Sneaky Throw Idiom ermöglicht die Umgehung
CheckedException
des Lambda-Ausdrucks. Das Einwickeln von aCheckedException
in aRuntimeException
ist nicht gut für eine strikte Fehlerbehandlung.Es kann als
Consumer
Funktion in einer Java-Sammlung verwendet werden.Hier ist eine einfache und verbesserte Version von Jibs Antwort .
Dies hüllt das Lambda nur in einen Wurf . Es lässt
CheckedException
alles zurückwerfenException
, was in dein Lambda geworfen wurde.Finden Sie eine vollständige Code und Unit - Tests hier .
quelle
Sie können hierfür ET verwenden . ET ist eine kleine Java 8-Bibliothek für die Konvertierung / Übersetzung von Ausnahmen.
Mit ET sieht es so aus:
ExceptionTranslator
Instanzen sind threadsicher und können von mehreren Komponenten gemeinsam genutzt werden. Sie können spezifischere Regeln für die Konvertierung von Ausnahmen konfigurieren (z. B.FooCheckedException -> BarRuntimeException
), wenn Sie möchten. Wenn keine anderen Regeln verfügbar sind, werden aktivierte Ausnahmen automatisch in konvertiertRuntimeException
.(Haftungsausschluss: Ich bin der Autor von ET)
quelle
Ich erlaube dem Benutzer, im Ausnahmefall den gewünschten Wert anzugeben. Ich habe also so etwas
Und das kann dann wie folgt aufgerufen werden:
quelle
Wenn es Ihnen nichts ausmacht, eine Bibliothek eines Drittanbieters mit cyclops-react zu verwenden , einer Bibliothek, zu der ich beitrage, können Sie die FluentFunctions- API zum Schreiben verwenden
ofChecked nimmt eine jOOλ CheckedFunction und gibt die Referenz zurück zu einem Standard-JDK (nicht markiert) java.util.function.Function.
Alternativ können Sie über die FluentFunctions-API weiter mit der erfassten Funktion arbeiten!
Zum Beispiel, um Ihre Methode auszuführen, sie bis zu fünf Mal zu wiederholen und ihren Status zu protokollieren, den Sie schreiben können
quelle
Standardmäßig erlaubt die Java 8- Funktion nicht, Ausnahmen auszulösen. Wie in mehreren Antworten vorgeschlagen, gibt es viele Möglichkeiten, dies zu erreichen. Eine Möglichkeit ist:
Definiere als:
Und fügen Sie
throws
odertry/catch
die gleiche Ausnahme in der Aufrufermethode hinzu.quelle
Erstellen Sie einen benutzerdefinierten Rückgabetyp, der die aktivierte Ausnahme weitergibt. Dies ist eine Alternative zum Erstellen einer neuen Schnittstelle, die die vorhandene Funktionsschnittstelle widerspiegelt, wobei die Methode der Funktionsschnittstelle geringfügig geändert wird.
Definition
CheckedValueSupplier
CheckedValue
Verwendungszweck
Was ist los?
Eine einzelne Funktionsschnittstelle, die eine aktivierte Ausnahme auslöst, wird erstellt (
CheckedValueSupplier
). Dies ist die einzige funktionale Schnittstelle, die geprüfte Ausnahmen zulässt. Alle anderen Funktionsschnittstellen nutzen dasCheckedValueSupplier
, um Code zu verpacken, der eine aktivierte Ausnahme auslöst.Die
CheckedValue
Klasse enthält das Ergebnis der Ausführung einer Logik, die eine aktivierte Ausnahme auslöst. Dies verhindert die Weitergabe einer aktivierten Ausnahme bis zu dem Punkt, an dem Code versucht, auf den Wert zuzugreifen, den eine InstanzCheckedValue
enthält.Die Probleme mit diesem Ansatz.
CheckedValue#get()
aufgerufen wird.Consumer et al
Einige funktionale Schnittstellen (
Consumer
zum Beispiel) müssen anders behandelt werden, da sie keinen Rückgabewert liefern.Funktion anstelle des Verbrauchers
Ein Ansatz besteht darin, anstelle eines Verbrauchers eine Funktion zu verwenden, die bei der Verarbeitung von Streams angewendet wird.
Eskalieren
Alternativ können Sie jederzeit zu a eskalieren
RuntimeException
. Es gibt andere Antworten, die die Eskalation einer aktivierten Ausnahme innerhalb von a abdeckenConsumer
.Nicht konsumieren.
Vermeiden Sie einfach alle funktionalen Schnittstellen und verwenden Sie eine altmodische for-Schleife.
quelle
Ich verwende eine überladene Dienstprogrammfunktion namens,
unchecked()
die mehrere Anwendungsfälle behandelt.EINIGE BEISPIELVERWENDUNGEN
UNTERSTÜTZUNG VON DIENSTLEISTUNGEN
quelle
Einige der angebotenen Lösungen verwenden ein generisches Argument von E, um den Typ der Ausnahme zu übergeben, die ausgelöst wird.
Gehen Sie noch einen Schritt weiter und übergeben Sie, anstatt den Typ der Ausnahme zu übergeben, einen Verbraucher des Ausnahmetyps, wie in ...
Sie können mehrere wiederverwendbare Varianten erstellen,
Consumer<Exception>
die die allgemeinen Anforderungen für die Ausnahmebehandlung Ihrer Anwendung abdecken.quelle
Ich werde etwas generisches tun:
Verwendungszweck:
quelle
Verwenden
Jool Library
oder sagenjOOλ library
vonJOOQ
. Es bietet nicht nur ungeprüfte Schnittstellen mit Ausnahmebehandlung, sondern bietet der Seq-Klasse auch viele nützliche Methoden.Außerdem enthält es funktionale Schnittstellen mit bis zu 16 Parametern. Außerdem bietet es eine Tupel-Klasse, die in verschiedenen Szenarien verwendet wird.
Jool Git Link
Speziell bei der Bibliothekssuche nach
org.jooq.lambda.fi.util.function
Paket. Es enthält alle Schnittstellen von Java-8 mit aktiviertem Voranschlag. Siehe unten als Referenz: -quelle
Ich bin der Autor einer winzigen Bibliothek mit etwas generischer Magie, um jede Java-Ausnahme irgendwo hin zu werfen, ohne sie fangen oder einwickeln zu müssen
RuntimeException
.Verwendungszweck:
unchecked(() -> methodThrowingCheckedException())
Quelle: https://github.com/qoomon/unchecked-exceptions-java
quelle
quelle
<code>/<code>
:)