it-swarm.com.de

Unfangbare ChuckNorrisException

Ist es möglich, einen Codeausschnitt in Java zu konstruieren, der ein hypothetisches Java.lang.ChuckNorrisException unfangbar?

Gedanken, die mir in den Sinn kamen, sind beispielsweise Interzeptoren oder aspektorientierte Programmierung .

586
Max Charas

Ich habe das nicht ausprobiert, deshalb weiß ich nicht, ob das JVM so etwas einschränken würde, aber vielleicht könnten Sie Code kompilieren, der ChuckNorrisException, aber zur Laufzeit geben Sie eine Klassendefinition von ChuckNorrisException an, die Throwable nicht erweitert.

AKTUALISIEREN:

Es funktioniert nicht Es wird ein Prüferfehler generiert:

Exception in thread "main" Java.lang.VerifyError: (class: TestThrow, method: ma\
in signature: ([Ljava/lang/String;)V) Can only throw Throwable objects
Could not find the main class: TestThrow.  Program will exit.

UPDATE 2:

Tatsächlich können Sie dies zum Laufen bringen, wenn Sie den Bytecode-Verifizierer deaktivieren! (-Xverify:none)

UPDATE 3:

Für diejenigen, die von zu Hause aus folgen, ist hier das vollständige Skript:

Erstellen Sie die folgenden Klassen:

public class ChuckNorrisException
    extends RuntimeException // <- Comment out this line on second compilation
{
    public ChuckNorrisException() { }
}

public class TestVillain {
    public static void main(String[] args) {
        try {
            throw new ChuckNorrisException();
        }
        catch(Throwable t) {
            System.out.println("Gotcha!");
        }
        finally {
            System.out.println("The end.");
        }
    }
}

Klassen kompilieren:

javac -cp . TestVillain.Java ChuckNorrisException.Java

Lauf:

Java -cp . TestVillain
Gotcha!
The end.

Auskommentieren "RuntimeException erweitern" und nur ChuckNorrisException.Java Neu kompilieren:

javac -cp . ChuckNorrisException.Java

Lauf:

Java -cp . TestVillain
Exception in thread "main" Java.lang.VerifyError: (class: TestVillain, method: main signature: ([Ljava/lang/String;)V) Can only throw Throwable objects
Could not find the main class: TestVillain.  Program will exit.

Ohne Bestätigung ausführen:

Java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"
309
jtahlborn

Nachdem ich darüber nachgedacht habe, habe ich erfolgreich eine unauffangbare Ausnahme erstellt. Ich habe mich jedoch dafür entschieden, es JulesWinnfield zu nennen, und nicht Chuck, weil es eine einzige Ausnahme ist, die Pilzwolken legt. Außerdem ist es vielleicht nicht genau das, was Sie sich vorgestellt haben, aber es ist sicher nicht zu fassen. Beobachten:

public static class JulesWinnfield extends Exception
{
    JulesWinnfield()
    {
        System.err.println("Say 'What' again! I dare you! I double dare you!");
        System.exit(25-17); // And you shall know I am the LORD
    }
}


public static void main(String[] args)
{       
    try
    {
        throw new JulesWinnfield();
    } 
    catch(JulesWinnfield jw)
    {
        System.out.println("There's a Word for that Jules - a bum");
    }
}

Et voila! Ungefangene Ausnahme.

Ausgabe:

lauf:

Sag noch mal "was! Du traust dich ja nicht! Ich wage dich doppelt!

Java Ergebnis: 8

ERFOLGREICH BAUEN (Gesamtzeit: 0 Sekunden)

Wenn ich etwas mehr Zeit habe, werde ich sehen, ob ich mir auch nichts anderes einfallen lassen kann.

Überprüfen Sie dies auch heraus:

public static class JulesWinnfield extends Exception
{
    JulesWinnfield() throws JulesWinnfield, VincentVega
    {
        throw new VincentVega();
    }
}

public static class VincentVega extends Exception
{
    VincentVega() throws JulesWinnfield, VincentVega
    {
        throw new JulesWinnfield();
    }
}


public static void main(String[] args) throws VincentVega
{

    try
    {
        throw new JulesWinnfield();
    }
    catch(JulesWinnfield jw)
    {

    }
    catch(VincentVega vv)
    {

    }
}

Verursacht einen Stapelüberlauf - Ausnahmen bleiben ebenfalls unberührt.

115
MikeTheLiar

Mit einer solchen Ausnahme wäre es natürlich obligatorisch, eine System.exit(Integer.MIN_VALUE); aus dem Konstruktor zu verwenden, da dies passieren würde, wenn Sie eine solche Ausnahme auslösen würden;)

85
Korgen

Jeder Code kann Throwable abfangen. Also nein, jede Ausnahme, die Sie erstellen, wird zu einer Unterklasse von Throwable und kann abgefangen werden.

46
Nathan Hughes
public class ChuckNorrisException extends Exception {
    public ChuckNorrisException() {
        System.exit(1);
    }
}

(Zugegeben, technisch gesehen diese Ausnahme wird eigentlich nie geworfen, aber eine richtige ChuckNorrisException kann nicht geworfen werden - sie wirft dich zuerst.)

35
fluffy

Jede Ausnahme, die Sie werfen, muss Throwable erweitern, damit sie immer abgefangen werden kann. Die Antwort lautet also nein.

Wenn Sie die Handhabung erschweren möchten, können Sie die Methoden getCause(), getMessage(), getStackTrace(), toString() überschreiben, um einen weiteren Java.lang.ChuckNorrisException Zu werfen.

28
mirelon

Meine Antwort basiert auf @ jtahlborns Idee, aber es ist ein voll funktionsfähiges Java Programm, das in eine JAR Datei gepackt werden kann und Wird sogar als Teil einer Webanwendung auf Ihrem bevorzugten Anwendungsserver bereitgestellt.

Zunächst definieren wir die Klasse ChuckNorrisException, damit die JVM nicht von Anfang an abstürzt (Chuck liebt es wirklich, JVMs BTW zum Absturz zu bringen :)

package chuck;

import Java.io.PrintStream;
import Java.io.PrintWriter;

public class ChuckNorrisException extends Exception {

    public ChuckNorrisException() {
    }

    @Override
    public Throwable getCause() {
        return null;
    }

    @Override
    public String getMessage() {
        return toString();
    }

    @Override
    public void printStackTrace(PrintWriter s) {
        super.printStackTrace(s);
    }

    @Override
    public void printStackTrace(PrintStream s) {
        super.printStackTrace(s);
    }
}

Nun geht die Klasse Expendables, um sie zu konstruieren:

package chuck;

import javassist.*;

public class Expendables {

    private static Class clz;

    public static ChuckNorrisException getChuck() {
        try {
            if (clz == null) {
                ClassPool pool = ClassPool.getDefault();
                CtClass cc = pool.get("chuck.ChuckNorrisException");
                cc.setSuperclass(pool.get("Java.lang.Object"));
                clz = cc.toClass();
            }
            return (ChuckNorrisException)clz.newInstance();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

Und zum Schluss die Klasse Main, um etwas in den Hintern zu treten:

package chuck;

public class Main {

    public void roundhouseKick() throws Exception {
        throw Expendables.getChuck();
    }

    public void foo() {
        try {
            roundhouseKick();
        } catch (Throwable ex) {
            System.out.println("Caught " + ex.toString());
        }
    }

    public static void main(String[] args) {
        try {
            System.out.println("before");
            new Main().foo();
            System.out.println("after");
        } finally {
            System.out.println("finally");
        }
    }
}

Kompilieren Sie es und führen Sie es mit folgendem Befehl aus:

Java -Xverify:none -cp .:<path_to_javassist-3.9.0.GA.jar> chuck.Main

Sie erhalten folgende Ausgabe:

before
finally

Kein Wunder - es ist doch ein Roundhouse-Kick :)

23
Wildfire

Im Konstruktor können Sie einen Thread starten, der wiederholt originalThread.stop (ChuckNorisException.this) aufruft.

Der Thread könnte die Ausnahme wiederholt abfangen, wirft sie jedoch so lange, bis sie stirbt.

15
Peter Lawrey

Nein. Alle Ausnahmen in Java müssen die Unterklasse Java.lang.Throwable Haben, und obwohl dies keine gute Praxis ist, können Sie jede Art von Ausnahme wie folgt abfangen:

try {
    //Stuff
} catch ( Throwable T ){
    //Doesn't matter what it was, I caught it.
}

Weitere Informationen finden Sie in der Dokumentation Java.lang.Throwable .

Wenn Sie versuchen, aktivierte Ausnahmen (Ausnahmen, die explizit behandelt werden müssen) zu vermeiden, sollten Sie Error oder RuntimeException als Unterklasse definieren.

13
VolatileDream

Tatsächlich ist die akzeptierte Antwort nicht so schön, weil Java muss ohne Überprüfung ausgeführt werden, d. H. Der Code würde unter normalen Umständen nicht funktionieren.

AspectJ zur Rettung für die echte Lösung!

Ausnahmeklasse:

package de.scrum_master.app;

public class ChuckNorrisException extends RuntimeException {
    public ChuckNorrisException(String message) {
        super(message);
    }
}

Aspekt:

package de.scrum_master.aspect;

import de.scrum_master.app.ChuckNorrisException;

public aspect ChuckNorrisAspect {
    before(ChuckNorrisException chuck) : handler(*) && args(chuck) {
        System.out.println("Somebody is trying to catch Chuck Norris - LOL!");
        throw chuck;
    }
}

Beispielanwendung:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        catchAllMethod();
    }

    private static void catchAllMethod() {
        try {
            exceptionThrowingMethod();
        }
        catch (Throwable t) {
            System.out.println("Gotcha, " + t.getClass().getSimpleName() + "!");
        }
    }

    private static void exceptionThrowingMethod() {
        throw new ChuckNorrisException("Catch me if you can!");
    }
}

Ausgabe:

Somebody is trying to catch Chuck Norris - LOL!
Exception in thread "main" de.scrum_master.app.ChuckNorrisException: Catch me if you can!
    at de.scrum_master.app.Application.exceptionThrowingMethod(Application.Java:18)
    at de.scrum_master.app.Application.catchAllMethod(Application.Java:10)
    at de.scrum_master.app.Application.main(Application.Java:5)
9
kriegaex

Eine Variante des Themas ist die überraschende Tatsache, dass Sie nicht deklarierte geprüfte Ausnahmen aus Java Code auslösen können. Da dies nicht in der Methodensignatur deklariert ist, lässt der Compiler nicht zu, dass Sie die Ausnahme selbst abfangen Sie können es jedoch als Java.lang.Exception abfangen.

Hier ist eine Hilfsklasse, mit der Sie alles werfen können, ob deklariert oder nicht:

public class SneakyThrow {
  public static RuntimeException sneak(Throwable t) {
    throw SneakyThrow.<RuntimeException> throwGivenThrowable(t);
  }

  private static <T extends Throwable> RuntimeException throwGivenThrowable(Throwable t) throws T {
    throw (T) t;
  }
}

Jetzt löst throw SneakyThrow.sneak(new ChuckNorrisException()); eine ChuckNorrisException aus, aber der Compiler beschwert sich

try {
  throw SneakyThrow.sneak(new ChuckNorrisException());
} catch (ChuckNorrisException e) {
}

informationen zum Abfangen einer Ausnahme, die nicht ausgelöst wird, wenn ChuckNorrisException eine aktivierte Ausnahme ist.

8

Die einzigen ChuckNorrisExceptions in Java) sollten OutOfMemoryError und StackOverflowError sein.

Sie können sie tatsächlich "abfangen", indem eine catch(OutOfMemoryError ex) ausgeführt wird, falls die Ausnahme ausgelöst wird, aber dieser Block wirft die Ausnahme automatisch erneut auf den Aufrufer.

Ich glaube nicht, dass public class ChuckNorrisError extends Error macht den Trick, aber Sie könnten es versuchen. Ich habe keine Dokumentation zum Erweitern von Error gefunden.

Is it possible to construct a snippet of code in Java that would make a hypothetical Java.lang.ChuckNorrisException uncatchable?

Ja, und hier ist die Antwort: Gestalten Sie Ihren Java.lang.ChuckNorrisException So, dass er keine Instanz von Java.lang.Throwable Ist. Warum? Ein nicht zu werfendes Objekt ist per Definition nicht zu fangen, da Sie niemals etwas fangen können, das niemals geworfen werden kann.

6
Thomas Eding

Sie können ChuckNorris intern oder privat halten und ihn einkapseln oder schlucken ...

try { doChuckAction(); } catch(ChuckNorrisException cne) { /*do something else*/ }

3
Jay

Zwei grundlegende Probleme bei der Ausnahmebehandlung in Java) bestehen darin, dass der Typ einer Ausnahme verwendet wird, um anzuzeigen, ob auf der Grundlage einer Ausnahme Maßnahmen ergriffen werden sollen, und dass alles, was auf der Grundlage einer Ausnahme Maßnahmen ergreift (z. B. " catch "es it) wird angenommen, um die zugrunde liegende Bedingung zu lösen. Es wäre nützlich, ein Mittel zu haben, mit dem ein Ausnahmeobjekt entscheiden könnte, welche Handler ausgeführt werden sollen, und ob die Handler, die bisher ausgeführt haben, die Dinge für die Gegenwart ausreichend aufgeräumt haben Methode zur Erfüllung der Exit-Bedingungen: Während dies verwendet werden könnte, um "unauffangbare" Ausnahmen zu erzeugen, würden zwei größere Verwendungszwecke darin bestehen, (1) Ausnahmen zu erzeugen, die nur dann als behandelt gelten, wenn sie von Code erfasst werden, der tatsächlich weiß, wie man damit umgeht sie und (2) ermöglichen eine vernünftige Behandlung von Ausnahmen, die in einem finally -Block auftreten (wenn ein FooException während eines finally -Blocks während des Abwickelns eines BarException, beide Ausnahmen sollten den Aufruf-Stack verbreiten, beide sollten abfangbar, aber unwin sein Es sollte so lange weiter gemacht werden, bis beide gefangen wurden. Leider glaube ich nicht, dass es eine Möglichkeit geben würde, vorhandenen Code zur Ausnahmebehandlung auf diese Weise zum Laufen zu bringen, ohne Dinge zu beschädigen.

3
supercat

Es ist leicht möglich, eine nicht erfasste Ausnahme für den aktuellen Thread zu simulieren. Dies löst das reguläre Verhalten einer nicht erfassten Ausnahme aus und erledigt den Job semantisch. Es wird jedoch nicht unbedingt die Ausführung des aktuellen Threads stoppen, da keine Ausnahme tatsächlich ausgelöst wird.

Throwable exception = /* ... */;
Thread currentThread = Thread.currentThread();
Thread.UncaughtExceptionHandler uncaughtExceptionHandler =
    currentThread.getUncaughtExceptionHandler();
uncaughtExceptionHandler.uncaughtException(currentThread, exception);
// May be reachable, depending on the uncaught exception handler.

Dies ist tatsächlich in (sehr seltenen) Situationen nützlich, zum Beispiel, wenn eine ordnungsgemäße Error -Handhabung erforderlich ist, die Methode jedoch von einem Framework aufgerufen wird, das Throwable abfängt (und verwirft).

1
dst

Rufen Sie System.exit (1) im finalize auf und werfen Sie einfach eine Kopie der Ausnahme von allen anderen Methoden, damit das Programm beendet wird.

0
Demi