Je sais comment créer une référence à une méthode qui a un String
paramètre et renvoie un int
, c'est:
Function<String, Integer>
Cependant, cela ne fonctionne pas si la fonction lève une exception, disons qu'elle est définie comme:
Integer myMethod(String s) throws IOException
Comment définirais-je cette référence?
Réponses:
Vous devrez effectuer l'une des opérations suivantes.
Si c'est votre code, définissez votre propre interface fonctionnelle qui déclare l'exception vérifiée:
et l'utiliser:
Sinon, encapsulez
Integer myMethod(String s)
dans une méthode qui ne déclare pas d'exception vérifiée:et alors:
ou:
la source
Consumer
ouFunction
si vous utilisez des méthodes par défaut - voir ma réponse ci-dessous.(String t) -> myWrappedMethod(t)
, la référence de méthodethis::myWrappedMethod
peut également être utilisée.Vous pouvez réellement étendre
Consumer
(etFunction
etc.) avec une nouvelle interface qui gère les exceptions - en utilisant les méthodes par défaut de Java 8 !Considérez cette interface (étend
Consumer
):Ensuite, par exemple, si vous avez une liste:
Si vous voulez le consommer (par exemple avec
forEach
) avec du code qui lève des exceptions, vous auriez traditionnellement mis en place un bloc try / catch:Mais avec cette nouvelle interface, vous pouvez l'instancier avec une expression lambda et le compilateur ne se plaindra pas:
Ou même simplement le lancer pour être plus succinct!:
Mise à jour : Il semble qu'il y ait une très belle partie de bibliothèque d'utilitaires de Durian appelée Erreurs qui peut être utilisée pour résoudre ce problème avec beaucoup plus de flexibilité. Par exemple, dans mon implémentation ci-dessus, j'ai explicitement défini la politique de gestion des erreurs (
System.out...
outhrow RuntimeException
), tandis que les erreurs de Durian vous permettent d'appliquer une politique à la volée via une large suite de méthodes utilitaires. Merci de le partager , @NedTwigg !.Exemple d'utilisation:
la source
Je pense que la
Errors
classe de Durian combine bon nombre des avantages des diverses suggestions ci-dessus.Pour inclure Durian dans votre projet, vous pouvez soit:
com.diffplug.durian:durian:3.3.0
Throwing.java
etErrors.java
la source
Ce n'est pas spécifique à Java 8. Vous essayez de compiler quelque chose d'équivalent à:
la source
Avis de non-responsabilité: je n'ai pas encore utilisé Java 8, lisez-le seulement.
Function<String, Integer>
ne lance pasIOException
, donc vous ne pouvez pas y mettre de codethrows IOException
. Si vous appelez une méthode qui attend aFunction<String, Integer>
, le lambda que vous passez à cette méthode ne peut pas lancerIOException
, point. Vous pouvez soit écrire un lambda comme celui-ci (je pense que c'est la syntaxe lambda, pas sûr):Ou, si la méthode à laquelle vous passez le lambda est celle que vous avez écrite vous-même, vous pouvez définir une nouvelle interface fonctionnelle et l'utiliser comme type de paramètre au lieu de
Function<String, Integer>
:la source
@FunctionalInterface
annotation n'est pas requise pour qu'elle soit utilisable pour les lambdas. Il est cependant recommandé de vérifier la santé mentale.Si cela ne vous dérange pas d'utiliser une bibliothèque tierce ( Vavr ), vous pouvez écrire
Il a également la soi-disant Try monad qui gère les erreurs:
Veuillez lire plus ici .
Avertissement: je suis le créateur de Vavr.
la source
Vous pouvez utiliser le décapsuleur
ou
la source
Vous pouvez cependant créer votre propre FunctionalInterface qui lance comme ci-dessous.
puis implémentez-le en utilisant Lambdas ou des références comme indiqué ci-dessous.
la source
Vous pouvez.
Étendre @marcg
UtilException
et ajouter des génériques<E extends Exception>
si nécessaire: de cette façon, le compilateur vous forcera à nouveau à ajouter des clauses throw et tout comme si vous pouviez lancer des exceptions vérifiées nativement sur les flux de java 8.la source
J'ai eu ce problème avec Class.forName et Class.newInstance dans un lambda, donc je viens de le faire:
À l'intérieur du lambda, au lieu d'appeler Class.forName ("myClass"). NewInstance () Je viens d'appeler uncheckedNewInstanceForName ("myClass")
la source
Une autre solution utilisant un wrapper Function serait de renvoyer soit une instance d'un wrapper de votre résultat, disons Success, si tout s'est bien passé, soit une instance de, disons Failure.
Un code pour clarifier les choses:
Un cas d'utilisation simple:
la source
Ce problème me dérange également; c'est pourquoi j'ai créé ce projet .
Avec lui, vous pouvez faire:
Il y a un total de 39 interfaces définies par le JDK qui ont un tel
Throwing
équivalent; ce sont tous des@FunctionalInterface
s utilisés dans les streams (la baseStream
mais aussiIntStream
,LongStream
etDoubleStream
).Et comme chacun d'eux étend son homologue non lanceur, vous pouvez également les utiliser directement dans les lambdas:
Le comportement par défaut est que lorsque votre lancement lambda lève une exception vérifiée, un
ThrownByLambdaException
est levé avec l'exception vérifiée comme cause. Vous pouvez donc capturer cela et obtenir la cause.D'autres fonctionnalités sont également disponibles.
la source
@FunctionalInterface public interface SupplierWithCE<T, X extends Exception> { T get() throws X; }
- de cette façon, l'utilisateur n'a pas besoin d'attraperThrowable
, mais l'exception vérifiée spécifique à la place.ThrownByLambdaException
, vous aurez l'exception d'origine comme cause (ou vous pouvez utiliserrethrow(...).as(MyRuntimeException.class)
)Throwing.runnable()
et d'autres, toujours avec des capacités de chaînageIl y a beaucoup de bonnes réponses déjà publiées ici. J'essaie juste de résoudre le problème avec une perspective différente. C'est juste mes 2 cents, veuillez me corriger si je me trompe quelque part.
La clause throws dans FunctionalInterface n'est pas une bonne idée
Je pense que ce n'est probablement pas une bonne idée d'appliquer les exceptions IOException pour les raisons suivantes
Cela me semble être un anti-pattern pour Stream / Lambda. L'idée est que l'appelant décidera du code à fournir et comment gérer l'exception. Dans de nombreux scénarios, l'exception IOException peut ne pas être applicable au client. Par exemple, si le client obtient de la valeur du cache / de la mémoire au lieu d'effectuer des E / S réelles.
De plus, la gestion des exceptions dans les flux devient vraiment hideuse. Par exemple, voici mon code ressemblera si j'utilise votre API
Moche n'est-ce pas? De plus, comme je l'ai mentionné dans mon premier point, que la méthode doSomeOperation peut ou non lancer IOException (selon l'implémentation du client / appelant), mais en raison de la clause throws de votre méthode FunctionalInterface, je dois toujours écrire le essayer-attraper.
Que dois-je faire si je sais vraiment que cette API lève IOException
Ensuite, nous confondons probablement FunctionalInterface avec des interfaces typiques. Si vous savez que cette API lèvera IOException, alors vous connaissez probablement aussi un comportement par défaut / abstrait. Je pense que vous devez définir une interface et déployer votre bibliothèque (avec une implémentation par défaut / abstraite) comme suit
Mais, le problème try-catch existe toujours pour le client. Si j'utilise votre API dans le flux, j'ai toujours besoin de gérer IOException dans un bloc try-catch hideux.
Fournissez une API conviviale par défaut comme suit
La méthode par défaut prend l'objet consommateur comme argument, qui sera chargé de gérer l'exception. Maintenant, du point de vue du client, le code ressemblera à ceci
Bonne droite? Bien sûr, un enregistreur ou une autre logique de gestion peut être utilisé à la place d'Exception :: printStackTrace.
Vous pouvez également exposer une méthode similaire à https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptionally-java.util.function.Function- . Cela signifie que vous pouvez exposer une autre méthode, qui contiendra l'exception de l'appel de méthode précédent. L'inconvénient est que vous rendez maintenant vos API statiques, ce qui signifie que vous devez gérer la sécurité des threads et que cela finira par devenir un problème de performances. Mais juste une option à considérer.
la source
Stream
exception déclenchée. Ainsi, j'aime l'idée d'avoir un gestionnaire d'exceptions et de filtrer les résultats qui ne sont pas valides. Notez que votre MyAmazingAPI est effectivement unFunctionalInterface
(vous pouvez donc ajouter l'annotation @FunctionalInterface). Vous pouvez également avoir une valeur par défaut au lieu d'utiliserOptional.empty()
.L'idiome de projection sournoise permet de contourner l'
CheckedException
expression Lambda. Envelopper unCheckedException
dans unRuntimeException
n'est pas bon pour une gestion stricte des erreurs.Il peut être utilisé comme
Consumer
fonction utilisée dans une collection Java.Voici une version simple et améliorée de la réponse de jib .
Cela enveloppe simplement le lambda dans un nouveau jet . Il fait
CheckedException
jeter tout ceException
qui a été jeté dans votre lambda.Trouvez un code complet et des tests unitaires ici .
la source
Vous pouvez utiliser ET pour cela. ET est une petite bibliothèque Java 8 pour la conversion / traduction d'exceptions.
Avec ET, cela ressemble à ceci:
ExceptionTranslator
les instances sont thread-safe et peuvent être partagées par plusieurs composants. Vous pouvez configurer des règles de conversion d'exception plus spécifiques (par exempleFooCheckedException -> BarRuntimeException
) si vous le souhaitez. Si aucune autre règle n'est disponible, les exceptions vérifiées sont automatiquement converties enRuntimeException
.(Avertissement: je suis l'auteur de ET)
la source
Ce que je fais, c'est de permettre à l'utilisateur de donner la valeur qu'il souhaite réellement en cas d'exception. J'ai donc quelque chose qui ressemble à ça
Et cela peut alors être appelé comme:
la source
Si cela ne vous dérange pas d'utiliser une bibliothèque tierce, avec cyclops-react , une bibliothèque à laquelle je contribue, vous pouvez utiliser l' API FluentFunctions pour écrire
ofChecked prend une fonction jOOλ CheckedFunction et renvoie la référence ramollie à une fonction JDK java.util.function.Function standard (non vérifiée).
Alternativement, vous pouvez continuer à travailler avec la fonction capturée via l'API FluentFunctions!
Par exemple, pour exécuter votre méthode, en la réessayant jusqu'à 5 fois et en enregistrant son état, vous pouvez l'écrire
la source
Par défaut, la fonction Java 8 ne permet pas de lever d'exception et, comme suggéré dans plusieurs réponses, il existe de nombreuses façons de le réaliser, dont l'une est:
Définir en tant que:
Et ajoutez
throws
outry/catch
la même exception dans la méthode de l'appelant.la source
Créez un type de retour personnalisé qui propagera l'exception vérifiée. Il s'agit d'une alternative à la création d'une nouvelle interface qui reflète l'interface fonctionnelle existante avec la légère modification d'une "exception de levée" sur la méthode de l'interface fonctionnelle.
Définition
CheckedValueSupplier
CheckedValue
Usage
Que se passe-t-il?
Une interface fonctionnelle unique qui lève une exception vérifiée est créée (
CheckedValueSupplier
). Ce sera la seule interface fonctionnelle qui autorise les exceptions vérifiées. Toutes les autres interfaces fonctionnelles tireront parti deCheckedValueSupplier
pour envelopper tout code qui lève une exception vérifiée.La
CheckedValue
classe contiendra le résultat de l'exécution de toute logique qui lève une exception vérifiée. Cela empêche la propagation d'une exception vérifiée jusqu'au moment où le code tente d'accéder à la valeur contenue dans une instanceCheckedValue
.Les problèmes avec cette approche.
CheckedValue#get()
soit appelée.Consumer et al
Quelques interfaces fonctionnelles (
Consumer
par exemple) doivent être traitées de manière différente car elles ne fournissent pas de valeur de retour.Fonction à la place du consommateur
Une approche consiste à utiliser une fonction au lieu d'un consommateur, qui s'applique lors de la gestion des flux.
Intensifier
Alternativement, vous pouvez toujours passer à a
RuntimeException
. Il existe d'autres réponses qui couvrent l'escalade d'une exception vérifiée de l'intérieur aConsumer
.Ne consommez pas.
Évitez simplement les interfaces fonctionnelles toutes ensemble et utilisez une boucle for-old-fashioned for.
la source
J'utilise une fonction utilitaire surchargée appelée
unchecked()
qui gère plusieurs cas d'utilisation.QUELQUES UTILISATIONS PAR EXEMPLE
SOUTIEN AUX UTILITAIRES
la source
Plusieurs des solutions proposées utilisent un argument générique de E pour passer le type de l'exception qui est levée.
Allez plus loin, et plutôt que de passer le type d'exception, passez un consommateur du type d'exception, comme dans ...
Vous pouvez créer plusieurs variantes réutilisables
Consumer<Exception>
qui couvriraient les besoins courants de gestion des exceptions de votre application.la source
Je vais faire quelque chose de générique:
usage:
la source
Utilisez
Jool Library
ou ditesjOOλ library
deJOOQ
. Il fournit non seulement des interfaces gérées d'exception non contrôlées, mais fournit également à la classe Seq de nombreuses méthodes utiles.En outre, il contient des interfaces fonctionnelles avec jusqu'à 16 paramètres. En outre, il fournit la classe Tuple qui est utilisée dans différents scénarios.
Lien Jool Git
Plus précisément dans la recherche de bibliothèque pour le
org.jooq.lambda.fi.util.function
package. Il contient toutes les interfaces de Java-8 avec Checked ajouté. Voir ci-dessous pour référence: -la source
Je suis l'auteur d'une petite bibliothèque avec une magie générique pour lancer n'importe quelle exception Java n'importe où sans avoir besoin de les attraper ni de les envelopper
RuntimeException
.Usage:
unchecked(() -> methodThrowingCheckedException())
source: https://github.com/qoomon/unchecked-exceptions-java
la source
la source
<code>/<code>
:)