Eine Methode, die ich in run () in einer Klasse aufrufe , die Runnable implementiert , soll eine Ausnahme auslösen .
Aber der Java-Compiler lässt mich das nicht und schlägt vor, ihn mit try / catch zu umgeben.
Das Problem ist, dass ich durch das Umgeben mit einem Versuch / Fang diesen bestimmten run () unbrauchbar mache . Ich tun will diese Ausnahme werfen.
Wenn ich throws
für run () selbst spezifiziere , beschwert sich der Compiler darüber Exception is not compatible with throws clause in Runnable.run()
.
Normalerweise bin ich völlig in Ordnung, wenn ich nicht zulasse , dass run () eine Ausnahme auslöst. Aber ich habe eine einzigartige Situation, in der ich diese Funktionalität haben muss.
Wie kann ich diese Einschränkung umgehen?
Antworten:
Wenn Sie eine Klasse übergeben möchten, die
Runnable
in dasThread
Framework implementiert wird , müssen Sie sich an die Regeln dieses Frameworks halten. Lesen Sie die Antwort von Ernest Friedman-Hill, warum es eine schlechte Idee ist, dies anders zu tun.Ich habe jedoch die Vermutung, dass Sie die
run
Methode direkt in Ihrem Code aufrufen möchten , damit Ihr aufrufender Code die Ausnahme verarbeiten kann.Die Antwort auf dieses Problem ist einfach. Verwenden Sie keine
Runnable
Schnittstelle aus der Thread-Bibliothek, sondern erstellen Sie eine eigene Schnittstelle mit der geänderten Signatur, mit der die aktivierte Ausnahme ausgelöst werden kann, zpublic interface MyRunnable { void myRun ( ) throws MyException; }
Sie können sogar einen Adapter erstellen, der diese Schnittstelle in real konvertiert
Runnable
(indem die aktivierte Ausnahme behandelt wird) und für die Verwendung im Thread-Framework geeignet ist.quelle
Runnable
ist a nur eine einfache Schnittstelle und wir können unsere eigene erstellen. Nicht nützlich für den Anwendungsfall des Threads, aber zum Übergeben verschiedener "ausführbarer" Codestücke ist dies perfekt.Sie können
Callable
stattdessen ein verwenden, es an ein sendenExecutorService
und auf das Ergebnis warten, dasFutureTask.isDone()
vom zurückgegeben wirdExecutorService.submit()
.Wenn
isDone()
true zurückgegeben wird, rufen Sie anFutureTask.get()
. Nun, wenn IhrCallable
geworfen hat eineException
dannFutureTask.get()
wiill ein WurfException
zu und die ursprüngliche Exception können Sie für den Zugriff verwendenException.getCause()
.quelle
Wenn
run()
eine aktivierte Ausnahme ausgelöst würde, was würde sie abfangen? Sie können diesenrun()
Aufruf nicht in einen Handler einschließen , da Sie den Code, der ihn aufruft, nicht schreiben.Sie können Ihre
run()
aktivierte Ausnahme in der Methode abfangen undRuntimeException
an ihrer Stelle eine nicht überprüfte Ausnahme (dh ) auslösen . Dadurch wird der Thread mit einem Stack-Trace beendet. Vielleicht ist es das, wonach du suchst.Wenn Sie stattdessen Ihre wollen
run()
Methode den Fehler irgendwo melden, dann können Sie nur eine Callback - Methode für das zur Verfügung stellenrun()
des Verfahrenscatch
Block zu nennen; Diese Methode könnte das Ausnahmeobjekt irgendwo speichern, und dann könnte Ihr interessierter Thread das Objekt an dieser Stelle finden.quelle
main()
eine aktivierte Ausnahme ausgelöst würde, was würde sie abfangen?" "Wennrun()
eine ungeprüfte Ausnahme ausgelöst würde, was würde sie fangen?"Ja, es gibt eine Möglichkeit, eine aktivierte Ausnahme von der
run()
Methode auszulösen, aber es ist so schrecklich, dass ich sie nicht freigeben werde.Folgendes können Sie stattdessen tun: Es verwendet denselben Mechanismus, den eine Laufzeitausnahme ausführen würde:
@Override public void run() { try { /* Do your thing. */ ... } catch (Exception ex) { Thread t = Thread.currentThread(); t.getUncaughtExceptionHandler().uncaughtException(t, ex); } }
Wie andere angemerkt haben , macht es keinen Sinn, eine Ausnahme auszulösen, wenn Ihre
run()
Methode wirklich das Ziel von a istThread
, da sie nicht beobachtbar ist. Das Auslösen einer Ausnahme hat den gleichen Effekt wie das Nichtauslösen einer Ausnahme (keine).Wenn es kein
Thread
Ziel ist, verwenden Sie es nichtRunnable
. Zum BeispielCallable
passt vielleicht besser.quelle
t.getUncaughtExceptionHandler().uncaughtException(t, ex);
um es in den Instrumentierungstestfall zu werfen. Das Hinzufügen dieser einen Zeile führt zum Absturz des Prozesses!. Ich weiß nicht warum.Thread.getDefaultUncaughtExceptionHandler()
zurücknull
? Wenn nicht, wie lautet die Art des Ergebnisses? Was passiert, wenn Sie anstelle eines AufrufsuncaughtException()
die aktivierte Ausnahme in aRuntimeException
einschließen und diese auslösen?Thread.getDefaultUncaughtExceptionHandler()
zurückkommenull
. Wenn nicht, stellt Android einen Standard bereit, um Berichte usw. anzubieten. Sie können ihn jedoch so einstellen, dass er das tut, was Sie wollen. Hier gibt es mehr Infos .@FunctionalInterface public interface CheckedRunnable<E extends Exception> extends Runnable { @Override default void run() throws RuntimeException { try { runThrows(); } catch (Exception ex) { throw new RuntimeException(ex); } } void runThrows() throws E; }
quelle
Einige Leute versuchen dich davon zu überzeugen, dass du dich an die Regeln halten musst. Hören Sie zu, aber ob Sie gehorchen, sollten Sie selbst entscheiden, abhängig von Ihrer Situation. Die Realität ist "Sie sollten nach den Regeln spielen" (nicht "Sie müssen nach den Regeln spielen"). Seien Sie sich nur bewusst, dass es Konsequenzen haben kann, wenn Sie sich nicht an die Regeln halten.
Die Situation gilt nicht nur in der Situation von
Runnable
, sondern mit Java 8 auch sehr häufig im Zusammenhang mit Streams und anderen Orten, an denen funktionale Schnittstellen eingeführt wurden, ohne die Möglichkeit, geprüfte Ausnahmen zu behandeln. Zum BeispielConsumer
,Supplier
,Function
,BiFunction
und haben so auf alle ohne Einrichtungen erklärt mit geprüften Ausnahmen zu behandeln.Was sind die Situationen und Optionen? Im folgenden Text
Runnable
steht er für jede Funktionsschnittstelle, die keine Ausnahmen deklariert oder Ausnahmen für den jeweiligen Anwendungsfall zu eingeschränkt deklariert.Runnable
selbst irgendwo deklariert und könnten durchRunnable
etwas anderes ersetzen .Runnable
mitCallable<Void>
. Grundsätzlich das Gleiche, darf aber Ausnahmen werfen; und mussreturn null
am Ende, was ein leichter Ärger ist.Runnable
durch Ihre eigene Gewohnheit zu ersetzen@FunctionalInterface
, die genau die gewünschten Ausnahmen auslösen kann.Callable<Void>
stattdessen verwenden könnenRunnable
.RuntimeException
.Sie können Folgendes versuchen. Es ist ein bisschen ein Hack, aber manchmal ist ein Hack das, was wir brauchen. Denn ob eine Ausnahme aktiviert oder deaktiviert werden soll, hängt von ihrem Typ ab, sollte aber praktisch von der Situation abhängen.
@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; }
Ich bevorzuge dies,
new RuntimeException(t)
weil es eine kürzere Stapelspur hat.Sie können jetzt tun:
executorService.submit((ThrowingRunnable) () -> {throw new Exception()});
Haftungsausschluss: Die Möglichkeit, ungeprüfte Casts auf diese Weise durchzuführen, wird in zukünftigen Java-Versionen möglicherweise tatsächlich entfernt, wenn Informationen zum Generika-Typ nicht nur zur Kompilierungszeit, sondern auch zur Laufzeit verarbeitet werden.
quelle
Ihre Anforderung macht keinen Sinn. Wenn Sie den aufgerufenen Thread über eine aufgetretene Ausnahme informieren möchten, können Sie dies über einen Rückrufmechanismus tun. Dies kann über einen Handler oder eine Sendung geschehen oder was auch immer Sie sich sonst noch vorstellen können.
quelle
Ich denke, ein Hörermuster könnte Ihnen bei diesem Szenario helfen. Wenn in Ihrer
run()
Methode eine Ausnahme auftritt , verwenden Sie einen Try-Catch-Block und senden Sie im Catch eine Benachrichtigung über ein Ausnahmeereignis. Und dann behandeln Sie Ihr Benachrichtigungsereignis. Ich denke, das wäre ein sauberer Ansatz. Dieser SO-Link gibt Ihnen einen hilfreichen Hinweis auf diese Richtung.quelle
Am einfachsten ist es, ein eigenes Ausnahmeobjekt zu definieren, das die
RuntimeException
Klasse anstelle derException
Klasse erweitert.quelle