87 votes

Existe-t-il un moyen de faire en sorte que la fonction run() de Runnable lève une exception ?

Une méthode que j'appelle dans exécuter() dans une classe qui implémente Runnable ) est conçu pour lever une exception.

Mais le compilateur Java ne me laisse pas faire et me suggère de l'entourer de try/catch.

Le problème est qu'en l'entourant d'un try/catch, je rends ce particulier exécuter() inutile. I do veut lancer cette exception.

Si je spécifie throws pour exécuter() lui-même, le compilateur se plaint que Exception is not compatible with throws clause in Runnable.run() .

D'ordinaire, je suis tout à fait d'accord pour ne pas laisser exécuter() lancer une exception. Mais j'ai une situation unique dans laquelle je dois avoir cette fonctionnalité.

Comment puis-je contourner cette limitation ?

4voto

Christian Hujer Points 31

Certaines personnes essaient de vous convaincre que vous devez respecter les règles. Écoutez, mais si vous obéissez, vous devez décider vous-même en fonction de votre situation. En réalité, "vous DEVRIEZ respecter les règles" (et non "vous DEVEZ respecter les règles"). Sachez simplement que si vous ne respectez pas les règles, il pourrait y avoir des conséquences.

Cette situation ne s'applique pas seulement à la situation de Runnable Avec Java 8, il est également très fréquent que des interfaces fonctionnelles soient introduites dans le contexte des flux et à d'autres endroits sans possibilité de traiter les exceptions vérifiées. Par exemple, Consumer , Supplier , Function , BiFunction et ainsi de suite, ont tous été déclarés sans possibilité de traiter les exceptions vérifiées.

Quelles sont donc les situations et les options ? Dans le texte ci-dessous, Runnable est représentatif de toute interface fonctionnelle qui ne déclare pas d'exceptions, ou qui déclare des exceptions trop limitées pour le cas d'utilisation en question.

  1. Vous avez déclaré Runnable quelque part vous-même, et vous pourriez remplacer Runnable avec quelque chose d'autre.
    1. Envisagez de remplacer Runnable con Callable<Void> . En gros, c'est la même chose, mais il est autorisé à lancer des exceptions et il doit return null à la fin, ce qui est un léger désagrément.
    2. Envisagez de remplacer Runnable avec votre propre @FunctionalInterface qui peut lancer exactement les exceptions que vous voulez.
  2. Vous avez utilisé une API, et des alternatives sont disponibles. Par exemple, certaines API Java sont surchargées, vous pouvez donc utiliser Callable<Void> au lieu de Runnable .
  3. Vous avez utilisé une API, et il n'y a pas d'alternatives. Dans ce cas, vous n'êtes pas encore à court d'options.
    1. Vous pouvez envelopper l'exception dans RuntimeException .
    2. Vous pouvez transformer l'exception en une RuntimeException en utilisant un cast non vérifié.

Vous pouvez essayer ce qui suit. C'est un peu un hack, mais parfois un hack est ce dont nous avons besoin. En effet, le fait qu'une exception doive être vérifiée ou non est défini par son type, mais la pratique devrait en fait être définie par la situation.

@FunctionalInterface
public interface ThrowingRunnable extends Runnable {
    @Override
    default void run() {
        try {
            tryRun();
        } catch (final Throwable t) {
            throwUnchecked(t);
        }
    }

    private static <E extends RuntimeException> void throwUnchecked(Throwable t) {
        throw (E) t;
    }

    void tryRun() throws Throwable;
}

Je préfère cela à new RuntimeException(t) parce qu'il a une trace de pile plus courte.

Vous pouvez maintenant le faire :

executorService.submit((ThrowingRunnable) () -> {throw new Exception()});

Avertissement : la possibilité d'effectuer des castings non vérifiés de cette manière pourrait en fait être supprimée dans les futures versions de Java, lorsque les informations de type générique seront traitées non seulement au moment de la compilation, mais aussi au moment de l'exécution.

0voto

Kumar Bibek Points 5768

Votre exigence n'a aucun sens. Si vous voulez informer l'appelé du thread d'une exception qui s'est produite, vous pouvez le faire par un mécanisme de rappel. Cela peut se faire par le biais d'un gestionnaire, d'une diffusion ou de tout autre mécanisme auquel vous pouvez penser.

0voto

Sujay Points 5506

Je pense qu'un modèle d'écouteur pourrait vous aider dans ce scénario. Dans le cas où une exception se produit dans votre run() utilisez un bloc try-catch et dans le catch envoyez une notification d'un événement d'exception. Puis traitez votre événement de notification. Je pense que c'est une approche plus propre. Ce lien SO vous donne une indication utile dans cette direction.

-1voto

joas Points 76

Le moyen le plus simple est de définir votre propre objet d'exception qui étend la fonction RuntimeException au lieu de la classe Exception classe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X