Uncatchable ChuckNorrisException

Czy jest możliwe skonstruowanie fragmentu kodu w Java , który uczyniłby hipotetyczną java.lang.ChuckNorrisException nie do zaakceptowania?

Myśli, które przychodzą na myśl, używają na przykład przechwytywaczy lub programowania zorientowanego na aspekt .

Author: Peter Mortensen, 2012-12-14

17 answers

Nie próbowałem tego, więc nie wiem, czy JVM ograniczyłby coś takiego, ale może mógłbyś skompilować kod, który rzuca ChuckNorrisException, ale w czasie wykonywania podaj definicję klasy ChuckNorrisException, która nie rozszerza Throwable.

Aktualizacja:

Nie działa. Generuje błąd weryfikatora:
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:

Właściwie, możesz to uruchomić, jeśli wyłączysz weryfikator kodu bajtowego! (-Xverify:none)

UPDATE 3:

Dla tych, którzy podążają z domu, oto pełny skrypt:

Utwórz następujące klasy:

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.");
        }
    }
}

Klasy kompilacji:

javac -cp . TestVillain.java ChuckNorrisException.java

Run:

java -cp . TestVillain
Gotcha!
The end.

Skomentuj "extends RuntimeException" i przekompiluj ChuckNorrisException.java tylko :

javac -cp . ChuckNorrisException.java

Run:

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.

Uruchom bez weryfikacji:

java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"
 306
Author: jtahlborn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-31 19:27:09

Po zastanowieniu się nad tym, udało mi się stworzyć wyjątek nie do zaakceptowania. Wybrałem jednak nazwę JulesWinnfield, a nie Chuck, ponieważ jest to jeden grzybowy-obłok-matka-wyjątek. Co więcej, może nie jest to dokładnie to, co miałeś na myśli, ale na pewno nie można go złapać. Obserwować:

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! nieobciążony wyjątek.

Wyjście:

Run:

Powiedz " co " jeszcze raz! Wyzywam cię! Wyzywam cię podwójnie!

Java Result: 8

Zbuduj pomyślnie (łączny czas: 0 sekund)

Kiedy będę miał trochę więcej czasu, zobaczę, czy nie wymyślę czegoś innego.

Zobacz też:

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)
    {

    }
}

Powoduje przepełnienie stosu - ponownie wyjątki pozostają nieobciążone.

 113
Author: MikeTheLiar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-16 04:03:49

Z takim wyjątkiem byłoby oczywiście obowiązkowe użycie System.exit(Integer.MIN_VALUE); z konstruktora, ponieważ tak by się stało, gdybyś wyrzucił taki wyjątek;)

 84
Author: Korgen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 17:23:34

Każdy kod może złapać Throwable. Więc nie, jakikolwiek wyjątek, który utworzysz, będzie podklasą Throwable i będzie podlegał złapaniu.

 45
Author: Nathan Hughes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 17:09:10
public class ChuckNorrisException extends Exception {
    public ChuckNorrisException() {
        System.exit(1);
    }
}

(przyznany, technicznie ten wyjątek nigdy nie jest w rzeczywistości wyrzucony, ale właściwy ChuckNorrisException nie może być wyrzucony-rzuca cię pierwszy.)

 34
Author: fluffy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-18 22:31:23

Każdy wyjątek, który rzucisz, musi rozszerzyć Throwable, aby zawsze mógł zostać złapany. Więc odpowiedź brzmi nie.

Jeśli chcesz utrudnić obsługę, możesz nadpisać metody getCause(), getMessage(), getStackTrace(), toString() aby rzucić Inny java.lang.ChuckNorrisException.

 28
Author: mirelon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 17:17:13

Moja odpowiedź opiera się na pomyśle @jtahlborn, ale jest to w pełni działający program Java, który można spakować do pliku JAR, a nawet wdrożyć na ulubionym serwerze aplikacji jako część aplikacji webowej.

Po pierwsze, zdefiniujmy ChuckNorrisException klasę, aby nie zawiesiła JVM od początku (Chuck naprawdę uwielbia rozbijać JVM-y BTW:)

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);
    }
}

Teraz idzie Expendables Klasa, aby ją skonstruować:

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);
        }
    }
}

I wreszcie Main klasa do kopania jakiś tyłek:

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");
        }
    }
}

Skompiluj i uruchom go za pomocą następującego polecenia:

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

Otrzymasz następujące wyjście:

before
finally

No surprise - to przecież kopniak okrągły:)

 23
Author: Wildfire,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-31 19:33:32

W konstruktorze można uruchomić wątek, który wielokrotnie wywołuje originalThread.stop (ChuckNorisException.this)

Wątek mógł wielokrotnie łapać wyjątek, ale rzucał go aż do śmierci.

 15
Author: Peter Lawrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 20:55:14

Nie. Wszystkie wyjątki w Javie muszą być podklasowane java.lang.Throwable, i chociaż może to nie być dobra praktyka, możesz wychwycić każdy typ WYJĄTKÓW w ten sposób:

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

Zobacz java.lang.Throwable dokumentacja aby uzyskać więcej informacji.

Jeśli próbujesz uniknąć zaznaczonych WYJĄTKÓW (tych, które muszą być jawnie obsługiwane), będziesz chciał podklasować Error lub RuntimeException.

 13
Author: VolatileDream,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-31 19:28:45

Wariantem motywu jest zaskakujący fakt, że można rzucać niezgłoszone zaznaczone wyjątki z kodu Javy. Ponieważ nie jest zadeklarowany w podpisie metod, kompilator nie pozwoli Ci złapać samego wyjątku, chociaż możesz go złapać jako java.lang.Wyjątek.

Oto Klasa pomocnicza, która pozwala rzucić wszystko, zadeklarowane lub nie:

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;
  }
}

Teraz throw SneakyThrow.sneak(new ChuckNorrisException()); rzuca ChuckNorrisException, ale kompilator narzeka w

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

O wyłapaniu wyjątku, który jest nie wyrzucone, jeśli ChuckNorrisException jest wyjątkiem zaznaczonym.

 8
Author: Hans-Peter Störr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-22 08:32:20

Właściwie przyjęta odpowiedź nie jest taka miła, ponieważ Java musi być uruchamiana bez weryfikacji, tzn. kod nie działałby w normalnych okolicznościach.

AspectJ na ratunek dla prawdziwego rozwiązania !

Exception class:

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;
    }
}

Przykładowe zastosowanie:

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!");
    }
}

Wyjście:

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)
 8
Author: kriegaex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-19 10:42:44

Jedynymi ChuckNorrisException s w Javie powinny być OutOfMemoryError i StackOverflowError.

Można je "złapać" w taki sposób, że catch(OutOfMemoryError ex) zostanie uruchomiony w przypadku wyrzucenia wyjątku, ale blok ten automatycznie zmieni wyjątek na wywołujący.

Nie sądzę, żeby to zadziałało, ale możesz spróbować. Nie znalazłem dokumentacji dotyczącej rozszerzenia Error
 7
Author: usr-local-ΕΨΗΕΛΩΝ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-15 12:01:31

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

Tak, A oto odpowiedź: Zaprojektuj Swój java.lang.ChuckNorrisException tak, aby nie był instancją java.lang.Throwable. Dlaczego? Nie do odrzucenia obiekt jest z definicji nie do uchwycenia, ponieważ nigdy nie można złapać czegoś, co nigdy nie może być rzucone.

 6
Author: Thomas Eding,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-18 08:19:17

Możesz trzymać Chucknorrisa wewnątrz lub prywatnie i otaczać go lub go otaczać...

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

 4
Author: Jay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-15 04:39:23

Dwa podstawowe problemy z obsługą WYJĄTKÓW w Javie to to, że używa on typu wyjątku, aby wskazać, czy działanie powinno być podjęte na jego podstawie, i że wszystko, co podejmuje działanie na podstawie wyjątku (tj. "złapać"go), jest uważane za rozwiązanie podstawowego warunku. Przydałoby się mieć sposób, za pomocą którego obiekt exception może decydować, które programy obsługi powinny wykonać, i czy programy obsługi, które wykonały do tej pory, wyczyściły rzeczy na tyle, aby obecna metoda spełniająca warunki wyjścia. Podczas gdy może to być użyte do tworzenia WYJĄTKÓW "uncatchable", dwa większe zastosowania to (1) Tworzenie wyjątków, które będą uważane za obsługiwane tylko wtedy, gdy zostaną przechwycone przez kod, który faktycznie wie, jak sobie z nimi radzić, oraz (2) zezwalanie na rozsądne obchodzenie się z wyjątkami, które występują w bloku finally (Jeśli FooException podczas bloku finally podczas rozwijania BarException, Oba wyjątki powinny propagować się w stosie wywołań; oba powinny być chwytliwe, ale odwijanie powinno trwać do momentu złapania obu). Niestety, nie sądzę, aby istniał sposób na to, aby istniejący kod obsługujący wyjątki działał w ten sposób bez niszczenia rzeczy.

 3
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-15 23:53:16

Łatwo jest symulować nieobciążony wyjątek w bieżącym wątku. Spowoduje to regularne zachowanie nieobciążonego wyjątku i w ten sposób zadanie zostanie wykonane semantycznie. To jednak niekoniecznie zatrzyma wykonywanie bieżącego wątku, ponieważ żaden wyjątek nie jest w rzeczywistości wyrzucany.

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

Jest to w rzeczywistości przydatne w (bardzo rzadkich) sytuacjach, na przykład, gdy wymagana jest właściwa Error Obsługa, ale metoda jest wywoływana z frameworka wyłapującego (i odrzucającego) wszelkie Throwable.

 1
Author: dst,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-09 00:37:23

System Połączeń.exit (1) w finalize i po prostu wyrzuć kopię wyjątku ze wszystkich innych metod, tak że program zakończy działanie.

 -1
Author: Demi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-18 01:23:38