web-dev-qa-db-fra.com

Comment lever une exception vérifiée à partir d'un thread Java?

Hé, j'écris une application réseau, dans laquelle je lis des paquets de certains formats binaires personnalisés. Et je commence un fil d'arrière-plan pour attendre les données entrantes. Le problème est que le compilateur ne me permet pas de mettre des exceptions de lancement de code (vérifiées) dans run(). Ça dit:

run () dans (...). L'écouteur ne peut pas implémenter run () dans Java.lang.Runnable; la méthode substituée ne lève pas Java.io.IOException

Je veux que l'exception tue le thread et le laisse prendre quelque part dans le thread parent. Est-ce possible à réaliser ou dois-je gérer toutes les exceptions à l'intérieur le thread?

40
mik01aj

Attention: cela peut ne pas répondre à vos besoins si vous devez utiliser le mécanisme d'exception.

Si je vous comprends bien, vous n'avez pas besoin de vérifier l'exception (vous avez accepté la réponse suggérant une exception non vérifiée), un modèle d'écoute simple serait-il plus approprié?

L'auditeur peut vivre dans le thread parent, et lorsque vous avez intercepté l'exception vérifiée dans le thread enfant, vous pouvez simplement en informer l'auditeur.

Cela signifie que vous avez un moyen d'exposer que cela se produira (par le biais de méthodes publiques) et que vous pourrez transmettre plus d'informations qu'une exception ne le permettra. Mais cela signifie qu'il y aura un couplage (quoique lâche) entre le parent et le thread enfant. Cela dépendrait de votre situation spécifique si cela aurait un avantage sur le conditionnement de l'exception cochée avec une exception non vérifiée.

Voici un exemple simple (du code emprunté à une autre réponse):

public class ThingRunnable implements Runnable {
    private SomeListenerType listener;
    // assign listener somewhere

    public void run() {
        try {
            while(iHaveMorePackets()) { 
                doStuffWithPacket();
            }
        } catch(Exception e) {
            listener.notifyThatDarnedExceptionHappened(...);
        }
    }
 }

Le couplage provient d'un objet dans le thread parent qui doit être de type SomeListenerType.

38
Grundlefleck

Pour pouvoir envoyer l'exception au thread parent, vous pouvez placer votre thread d'arrière-plan dans un Callable (il permet de lever également des exceptions vérifiées) que vous passez ensuite au submit méthode de certains exécuteurs . La méthode de soumission renverra un Future que vous pouvez ensuite utiliser pour obtenir l'exception (sa méthode get lancera un ExecutionException qui contient l'exception d'origine ).

48
Esko Luontola

Cette réponse est basée sur celle d'Esko Luontola mais elle fournit un exemple de travail.

Contrairement à la méthode run () de l'interface Runnable, la méthode call () de Callable permet de lever quelques exceptions. Voici un exemple d'implémentation:

public class MyTask implements Callable<Integer> {

    private int numerator;
    private int denominator;

    public MyTask(int n, int d) {
        this.numerator = n;
        this.denominator = d;
    }

    @Override
    // The call method may throw an exception
    public Integer call() throws Exception {
        Thread.sleep(1000);
        if (denominator == 0) {
            throw new Exception("cannot devide by zero");
        } else {
            return numerator / denominator;
        }
    }

}

Executor fournit un mécanisme pour exécuter un Callable à l'intérieur d'un thread et pour gérer tout type d'exceptions:

public class Main {

    public static void main(String[] args) {

        // Build a task and an executor
        MyTask task = new MyTask(2, 0);
        ExecutorService threadExecutor = Executors.newSingleThreadExecutor();

        try {
            // Start task on another thread
            Future<Integer> futureResult = threadExecutor.submit(task);

            // While task is running you can do asynchronous operations
            System.out.println("Something that doesn't need the tasks result");

            // Now wait until the result is available
            int result = futureResult.get();
            System.out.println("The result is " + result);
        } catch (ExecutionException e) {
            // Handle the exception thrown by the child thread
            if (e.getMessage().contains("cannot devide by zero"))
                System.out.println("error in child thread caused by zero division");
        } catch (InterruptedException e) {
            // This exception is thrown if the child thread is interrupted.
            e.printStackTrace();
        }
    }
}
33
a.b.d

Ce que je fais est d'attraper l'exception dans le fil et de la stocker en tant que variable membre de Runnable. Cette exception est ensuite exposée via un getter sur le Runnable. J'analyse ensuite tous les fils du parent pour voir s'il y a des exceptions et je prends les mesures appropriées.

7
Don Branson

Si vous ne pouvez vraiment rien faire d'utile lorsque l'exception est levée, vous pouvez envelopper l'exception vérifiée dans une RuntimeException.

try {
    // stuff
} catch (CheckedException yourCheckedException) {
    throw new RuntimeException("Something to explain what is happening", yourCheckedException);
}
3
Simon Groenewolt

le thread ne peut pas lever l'exception vers un autre thread (ni vers le thread principal). et vous ne pouvez pas faire en sorte que la méthode run () héritée lève des exceptions vérifiées car vous ne pouvez lever que moins que le code hérité, pas plus.

3
rmn

Si le code de votre thread lance une RuntimeExpection, vous n'avez pas besoin d'ajouter une exception run ().

Mais utilisez cette solution uniquement lorsque cela est approprié car cela peut être une mauvaise pratique: http://Java.Sun.com/docs/books/tutorial/essential/exceptions/runtime.html

Toute exception RuntimeException ou exception non vérifiée peut vous aider. Vous devrez peut-être créer votre propre RuntimeException

1
Nettogrof

En supposant que votre code est dans une sorte de boucle, vous écririez:

public class ThingRunnable implements Runnable {
  public void run() {
    try {
      while(iHaveMorePackets()) { 
        doStuffWithPacket()
      }
    } catch(Exception e) {
      System.out.println("Runnable terminating with exception" + e );
    }
  }
}

L'exception vous fera automatiquement sortir de votre boucle et à la fin de la méthode run (), le thread s'arrêtera.

0
AlBlue