Gibt es eine Möglichkeit, eine Ausnahme auszulösen, ohne die Throws-Deklaration hinzuzufügen?

80

Ich habe die folgende Situation.

Ich habe eine Java-Klasse, die von einer anderen Basisklasse erbt und eine Methode überschreibt. Die Basismethode löst keine Ausnahmen aus und hat daher keine throws ...Deklaration.

Jetzt sollte meine eigene Methode in der Lage sein, Ausnahmen auszulösen, aber ich habe entweder die Wahl dazu

  • Schluck die Ausnahme
  • Fügen Sie eine Wurfdeklaration hinzu

Beides ist nicht zufriedenstellend, da das erste die Ausnahme stillschweigend ignorieren würde (ok, ich könnte eine Protokollierung durchführen) und das zweite aufgrund der unterschiedlichen Methodenheader Compilerfehler erzeugen würde.

public class ChildClass extends BaseClass {

        @Override 
        public void SomeMethod() {
            throw new Exception("Something went wrong");
        }
}
Jürgen Steinblock
quelle

Antworten:

97

Sie können ungeprüfte Ausnahmen auslösen, ohne sie deklarieren zu müssen, wenn Sie dies wirklich möchten. Nicht aktivierte Ausnahmen gelten RuntimeException. Erweiterbare Throwables Errorsind ebenfalls deaktiviert, sollten jedoch nur für vollständig nicht behandelbare Probleme verwendet werden (z. B. ungültiger Bytecode oder nicht genügend Speicher).

Als speziellen Fall wurde Java 8 UncheckedIOExceptionzum Umschließen und erneuten Werfen hinzugefügt IOException.

OrangeDog
quelle
1
Funktioniert hervorragend, ich muss eine RuntimeException erneut auslösen, da die Ausnahme von einer anderen Methode stammt, aber es funktioniert hervorragend, danke.
Jürgen Steinblock
42

Hier ist ein Trick:

class Utils
{
    @SuppressWarnings("unchecked")
    private static <T extends Throwable> void throwException(Throwable exception, Object dummy) throws T
    {
        throw (T) exception;
    }

    public static void throwException(Throwable exception)
    {
        Utils.<RuntimeException>throwException(exception, null);
    }
}

public class Test
{
    public static void main(String[] args)
    {
        Utils.throwException(new Exception("This is an exception!"));
    }
}
Eng.Fouad
quelle
Ich frage mich, wie das funktioniert? Ich werde etwas recherchieren, aber haben Sie Ressourcen, die mir helfen könnten? :-)
holmicz
T als RuntimeException abgeleitet. Beantwortet hier stackoverflow.com/questions/41380656/… und hier stackoverflow.com/questions/31316581/…
Seenimurugan
1
Super Trick! Dieser Trick kann auch auf Lambda-Ausdrücke / -Blöcke angewendet werden, um der SAM-Schnittstelle die Methode der geprüften Ausnahme ohne throwsDeklarationen zuzuweisen.
JasonMing
hat den zusätzlichen Super-Bonus, nicht mit unsicheren Dingen umgehen zu müssen.
lscoughlin
Warum brauchen Sie den Dummy-Parameter? Könnte dies auch ohne die generische Methode funktionieren?
Kiruahxh
28

Eine dritte Möglichkeit besteht darin, die Ausnahmeprüfung zu deaktivieren (genau wie es die Standard-API manchmal tun muss) und die geprüfte Ausnahme in Folgendes zu verpacken RuntimeException:

throw new RuntimeException(originalException);

Möglicherweise möchten Sie eine spezifischere Unterklasse von verwenden RuntimeException.

Michael Borgwardt
quelle
10

Ich möchte nur eine alternative Antwort hinzufügen, nur als FYI :

Ja, es gibt eine Möglichkeit throws, mithilfe der sun.misc.UnsafeKlasse eine aktivierte Ausnahme auszulösen, ohne die Deklaration hinzuzufügen . Dies wird im folgenden Blogbeitrag beschrieben:

Wirf eine aktivierte Ausnahme aus einer Methode aus, ohne sie zu deklarieren

Beispielcode:

public void someMethod() {
  //throw a checked exception without adding a "throws"
  getUnsafe().throwException(new IOException());
}

private Unsafe getUnsafe() {
  try {
    Field field = Unsafe.class.getDeclaredField("theUnsafe");
    field.setAccessible(true);
    return (Unsafe) field.get(null);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

Dies wird jedoch nicht empfohlen. Es ist besser, eine ungeprüfte Ausnahme einzuschließen, wie in einigen anderen Antworten beschrieben.

Dogbane
quelle
3
Es gibt einen Grund, warum sie diese Klasse nennen Unsafe.
OrangeDog
4

Warum werfen Sie keine ungeprüfte Ausnahme? Dies muss nicht deklariert werden.

Zwei Alternativen sind

  • Wrap mit einer aktivierten Ausnahme mit einer nicht aktivierten.
  • Lassen Sie den Compiler nicht wissen, dass Sie eine aktivierte Ausnahme auslösen, z. B. Thread.currentThread (). stop (e);
  • In Java 6 können Sie die Ausnahme erneut auslösen, wenn dies der Fall ist finalund der Compiler weiß, welche überprüften Ausnahmen Sie möglicherweise abgefangen haben.
  • In Java 7 können Sie eine Ausnahme erneut auslösen, wenn sie tatsächlich endgültig ist, dh Sie ändern sie nicht im Code.

Letzteres ist nützlicher, wenn Sie eine Prüfausnahme in Ihrem Code auslösen und in Ihrem aufrufenden Code abfangen, die dazwischen liegenden Ebenen jedoch nichts über die Ausnahme wissen.

Peter Lawrey
quelle
Die zweite Methode ist ebenfalls interessant. Aber im Moment ist es genau das, was ich brauche, die Ausnahme zu verpacken.
Jürgen Steinblock
@OrangeDog, da Sie dies gelesen haben, können Sie mir sagen, was der Unterschied zwischen der Verwendung von stop () für den aktuellen Thread und dem Auslösen einer umschlossenen Ausnahme ist. ;)
Peter Lawrey
"Die folgende Methode ist verhaltensmäßig identisch mit der Throw-Operation von Java, umgeht jedoch die Versuche des Compilers, sicherzustellen, dass die aufrufende Methode alle überprüften Ausnahmen deklariert hat, die sie möglicherweise auslöst." Wie wird die Ausnahme besser umbrochen?
Peter Lawrey
"Durch das Stoppen eines Threads werden alle von ihm gesperrten Monitore entsperrt. Wenn sich eines der zuvor von diesen Monitoren geschützten Objekte in einem inkonsistenten Zustand befand, können andere Threads diese Objekte jetzt in einem inkonsistenten Zustand anzeigen. [...] Im Gegensatz dazu andere ungeprüfte Ausnahmen [...] Der Benutzer hat keine Warnung, dass sein Programm beschädigt sein könnte. "
OrangeDog
4

Ja, es gibt ein Warum, aber es wird überhaupt nicht empfohlen, was Sie verwenden können:

Unsicheres Java-Paket

getUnsafe().throwException(new IOException());

Diese Methode löst eine geprüfte Ausnahme aus, aber Ihr Code muss sie nicht abfangen oder erneut auslösen. Genau wie zur Laufzeitausnahme.

Ahmad Al-Kurdi
quelle
2

Hier ist ein Beispiel für das Abfangen aktivierter Ausnahmen und das Umschließen dieser in eine nicht aktivierte Ausnahme:

public void someMethod() {
   try {
      doEvil();
   }
   catch (IOException e)
   {
       throw new RuntimeException(e);
   }
}
Jason S.
quelle
-1

Sie können die Ausnahme mit dem try-catch-Block in Ihrer überschriebenen Methode abfangen. dann müssen Sie keine throws- Anweisung deklarieren.

Erhan Bagdemir
quelle
2
sicher, aber dann würde ich die Ausnahme schlucken, die genau das Gegenteil von dem ist, was ich erreichen möchte;)
Jürgen Steinblock
-1

Sie können jede von RuntimeException oder RuntimeException selbst abgeleitete Ausnahme verwenden

oder

Verwenden Sie einen Try-Block für den Code zum Auslösen von Ausnahmen und behandeln Sie ihn dort

fmucar
quelle