2012-07-20 11 views
51

Eine Methode, die ich in run() in einer Klasse aufrufen, die implementiert Runnable) ist entworfen, um eine Ausnahme zu werfen.Gibt es eine Möglichkeit, Runnable Run() eine Ausnahme auszulösen?

Aber der Java-Compiler lässt mich das nicht und schlägt vor, dass ich es mit try/catch umgebe.

Das Problem ist, dass durch das Umgeben es mit einem Versuch/Fang ich , dass insbesondererun() nutzlos machen. I tun möchte diese Ausnahme werfen.

Wenn ich throws für run() selbst angeben, beschwert sich der Compiler, dass Exception is not compatible with throws clause in Runnable.run().

Normalerweise bin ich völlig in Ordnung mit run() werfen keine Ausnahme. Aber ich habe eine einzigartige Situation, in der ich diese Funktionalität haben muss.

Wie kann ich diese Einschränkung umgehen?

+0

Neben anderen Antworten, Fortschritt der Aufgabe zu verfolgen, können Sie Verwenden Sie die FutureTask-Klasse. – JProgrammer

+0

Nicht-android Java-Frage: http://stackoverflow.com/questions/1369204/how-to-drow-a-checked-exception-from-a-java-thread?lq=1 –

Antwort

15

Wenn Sie eine Klasse übergeben möchten, die Runnable in das Thread Framework implementiert, dann müssen Sie nach den Regeln dieses Frameworks spielen, siehe Ernest Friedman-Hill's Antwort, warum es sonst eine schlechte Idee ist.

Ich habe eine Ahnung, dass Sie run Methode direkt in Ihrem Code aufrufen möchten, so dass Ihr aufrufender Code die Ausnahme verarbeiten kann.

Die Antwort auf dieses Problem ist einfach. Verwenden Sie nicht die Schnittstelle Runnable aus der Thread-Bibliothek, sondern erstellen Sie stattdessen Ihre eigene Schnittstelle mit der geänderten Signatur, die es ermöglicht, dass eine überprüfte Ausnahme ausgelöst wird, z.

public interface MyRunnable 
{ 
    void myRun () throws MyException; 
} 

Sie können sogar einen Adapter erstellen, die diese Schnittstelle zum realen Runnable konvertiert (durch geprüfte Ausnahmebehandlung) geeignet für den Einsatz in Thread-Framework.

+22

Wie würde der Thread diese Schnittstelle verwenden? –

+0

Eine solche einfache Lösung kam nur durch das Nicht-Denken "in der Box" zustande. Natürlich ist ein 'Runnable' nur eine einfache Schnittstelle und wir können unsere eigenen erstellen. Nicht nützlich für den Thread Use-Case, aber für die Übergabe von verschiedenen "runnable" Chunks um diesen Code ist perfekt. –

16

Wenn run() eine geprüfte Ausnahme auswirft, was würde es fangen? Sie können diesen run() Aufruf in einem Handler nicht einschließen, da Sie den Code nicht schreiben, der es aufruft.

Sie können Ihre geprüfte Ausnahme in der run()-Methode abfangen und stattdessen eine unchektierte Ausnahme (d. H. RuntimeException) auslösen. Dies beendet den Thread mit einer Stack-Trace; Vielleicht ist es das, wonach Sie suchen.

Wenn Sie stattdessen möchten, dass Ihre run() Methode den Fehler irgendwo melden, dann können Sie nur eine Callback-Methode für die run()catch Block-Methode zur Verfügung stellen zu nennen; Diese Methode könnte das Ausnahmeobjekt irgendwo speichern, und dann könnte Ihr interessierter Thread das Objekt an diesem Ort finden.

-1

Ihre Anforderung ergibt keinen Sinn. Wenn Sie den Aufruf des Threads über eine aufgetretene Ausnahme benachrichtigen möchten, können Sie dies über einen Rückrufmechanismus tun. Dies kann durch einen Handler oder eine Sendung oder was auch immer Sie denken können.

0

Ich denke, ein listener pattern könnte Ihnen bei diesem Szenario helfen. Wenn eine Ausnahme in Ihrer run()-Methode auftritt, verwenden Sie einen try-catch-Block, und senden Sie im catch eine Benachrichtigung über ein Ausnahmeereignis. Und dann handle mit deinem Benachrichtigungsereignis. Ich denke, das wäre ein sauberer Ansatz. This SO link gibt Ihnen einen hilfreichen Zeiger in diese Richtung.

59

können Sie einen Callable stattdessen verwenden, um es zu einem ExecutorService und wartet auf Ergebnis mit FutureTask.isDone() zurück durch die ExecutorService.submit() einreichen.

Wenn isDone() Wahr zurückgibt, rufen Sie FutureTask.get(). Nun, wenn Ihre Callable hat eine Exception geworfen dann FutureTask.get() will eine Exception auch zu werfen und die ursprüngliche Ausnahme können Sie mit Exception.getCause() zugreifen.

+5

Würde gerne ein Codebeispiel sehen – gromit190

13

Ja, es gibt eine Möglichkeit, eine checked Ausnahme von der run() Methode zu werfen, aber es ist so schrecklich, ich werde es nicht teilen.

Hier ist, was Sie stattdessen tun können; es verwendet den gleichen Mechanismus, der eine Laufzeitausnahme ausüben würde:

@Override 
public void run() { 
    try { 
    /* Do your thing. */ 
    ... 
    } catch (Exception ex) { 
    Thread t = Thread.currentThread(); 
    t.getUncaughtExceptionHandler().uncaughtException(t, ex); 
    } 
} 

Wie andere erwähnt haben, wenn Ihr run() Methode wirklich das Ziel eines Thread ist, da in Auslösen einer Ausnahme keinen Sinn, weil es nicht beobachtbar ist; Das Auslösen einer Ausnahme hat denselben Effekt wie das Auslösen einer Ausnahme (keine).

Wenn es kein Thread Ziel ist, verwenden Sie nicht Runnable. Zum Beispiel ist vielleicht Callable eine bessere Passform.

+0

Aber führt dies dazu, dass der Prozess abstürzt, wenn er wirft? –

+0

@DineshVG Nein, nur ein Fehler in der JVM kann einen echten Absturz verursachen. Der Standardausnahmebehandler druckt nur die Ausnahme aus. Wenn Sie daran gewöhnt sind, den Prozess danach zu sehen, liegt das daran, dass dieser Thread der einzige laufende Thread war und beendet wurde. – erickson

+0

Ich versuchte (in Android-Instrumentierung Testfälle) mit dieser für einen Soap-Aufruf, wo, wenn ich eine 400 von Soap-Aufruf, ich eine Ausnahme werfen. Dieser Soap-Call wird von einem Thread aufgerufen, während der Testfall gestartet wird. Dieser Thread verwendet diese 't.getUncaughtExceptionHandler(). UncaughtException (t, ex);', um sie dem Instrumentierungs-Testfall zu übergeben. Das Hinzufügen dieser Zeile führt zum Absturz des Prozesses! Ich weiß nicht warum. –

-1

Die einfachste Möglichkeit besteht darin, ein eigenes Ausnahmeobjekt zu definieren, das die Klasse RuntimeException anstelle der Klasse Exception erweitert.

+0

Und wie würden Sie dieses RuntimeException erhalten, wenn es auftritt, mein lieber Herr? – Dormouse

+0

Das allein beantwortet die Frage nicht. –

0

Hier ist, wie man eine Klasse mit geprüften Ausnahmen wickeln konnte und noch in der Lage sein zu decken/testen Sie die ganze Klasse

public final class Json { 

private Json() { 
} 

public static ObjectMapper standard() { 
    final ObjectMapper objectMapper = new ObjectMapper(); 
    objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); 
    objectMapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL); 
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 
    objectMapper.setDefaultSetterInfo(JsonSetter.Value.construct(Nulls.AS_EMPTY, Nulls.AS_EMPTY)); 
    objectMapper.findAndRegisterModules(); 
    return objectMapper; 
} 

public static String writeValueAsString(final Object value) { 
    return transformException(() -> standard().writeValueAsString(value)); 
} 

public static String writeValueAsStringPretty(final Object value) { 
    return transformException(() -> standard().writerWithDefaultPrettyPrinter().writeValueAsString(value)); 
} 

static String transformException(final Callable<String> action) { 
    try { 
     return action.call(); 
    } catch (Exception e) { 
     throw new IllegalStateException(e); 
    } 
} 

}

Verwandte Themen