No atrapable ChuckNorrisException


¿Es posible construir un fragmento de código en Java que haría que un java.lang.ChuckNorrisException hipotético sea imposible de atrapar?

Los pensamientos que vinieron a la mente están usando, por ejemplo, interceptores o programación orientada a aspectos.

Author: Peter Mortensen, 2012-12-14

17 answers

No he probado esto, por lo que no se si la JVM restringiría algo como esto, pero tal vez podrías compilar código que arroja ChuckNorrisException, pero en tiempo de ejecución proporcionar una definición de clase de ChuckNorrisException que no extiende Throwable.

ACTUALIZACIÓN:

No funciona. Genera un error de verificador:

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.

ACTUALIZACIÓN 2:

¡En realidad, puede hacer que esto funcione si deshabilita el verificador de código de bytes! (-Xverify:none)

ACTUALIZAR 3:

Para los que siguen desde casa, aquí está el script completo:

Cree las siguientes clases:

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

Compile clases:

javac -cp . TestVillain.java ChuckNorrisException.java

Ejecutar:

java -cp . TestVillain
Gotcha!
The end.

Comenta "extiende RuntimeException" y recompila ChuckNorrisException.java solo :

javac -cp . ChuckNorrisException.java

Ejecutar:

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.

Ejecutar sin verificación:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-31 19:27:09

Después de haber reflexionado sobre esto, he creado con éxito una excepción inalcanzable. Elegí nombrarlo JulesWinnfield, sin embargo, en lugar de Chuck, porque es una excepción madre que pone nubes de hongos. Además, puede que no sea exactamente lo que tenías en mente, pero ciertamente no se puede atrapar. Observe:

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! Excepción no capturada.

Salida:

Ejecutar:

Decir " Qué " de nuevo! ¡Te reto! ¡Te reto doble!

Resultado de Java: 8

BUILD SUCCESSFUL (tiempo total: 0 segundos)

Cuando tenga un poco más de tiempo, veré si puedo llegar a otra cosa, también.

También, mira esto:

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

    }
}

Provoca un desbordamiento de pila - de nuevo, las excepciones permanecen sin capturar.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-16 04:03:49

Con tal excepción obviamente sería obligatorio usar un System.exit(Integer.MIN_VALUE); del constructor porque esto es lo que pasaría si lanzas tal excepción;)

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-14 17:23:34

Cualquier código puede atrapar lanzable. Así que no, cualquier excepción que crees va a ser una subclase de Lanzable y estará sujeta a ser atrapada.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-14 17:09:10
public class ChuckNorrisException extends Exception {
    public ChuckNorrisException() {
        System.exit(1);
    }
}

(Concedido, técnicamente esta excepción nunca se lanza realmente, pero un ChuckNorrisException apropiado no se puede lanzar you te lanza primero.)

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-18 22:31:23

Cualquier excepción que lance tiene que extender Lanzable, por lo que siempre puede ser atrapada. Así que la respuesta es no.

Si desea que sea difícil de manejar, puede anular los métodos getCause(), getMessage(), getStackTrace(), toString() para lanzar otro 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-14 17:17:13

Mi respuesta se basa en la idea de @jtahlborn, pero es un programa completamente funcional Java, que puede empaquetarse en un archivo JAR e incluso desplegarse en su servidor de aplicaciones favorito como parte de una aplicación web .

En primer lugar, vamos a definir ChuckNorrisException clase para que no se bloquee JVM desde el principio (Chuck realmente ama estrellarse JVM 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);
    }
}

Ahora va Expendables clase para construirlo:

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

Y finalmente la clase Main para patear algunos culos:

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

Compilar y ejecutar con el siguiente comando:

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

Obtendrá la siguiente salida:

before
finally

No es ninguna sorpresa-es una patada redonda después de todo:)

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-31 19:33:32

En el constructor puedes iniciar un subproceso que llame repetidamente a originalThread.stop (ChuckNorisException.this)

El hilo podría atrapar la excepción repetidamente, pero seguiría lanzándola hasta que muera.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-14 20:55:14

No. Todas las excepciones en Java deben subclase java.lang.Throwable, y aunque puede no ser una buena práctica, puede capturar cada tipo de excepción de esta manera:

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

Véase el java.lang.Throwable documentación para más información.

Si está tratando de evitar excepciones marcadas (que deben ser manejadas explícitamente), entonces querrá subclase Error, o 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-31 19:28:45

Una variante del tema es el hecho sorprendente de que puede lanzar excepciones verificadas no declaradas del código Java. Dado que no está declarado en la firma de métodos, el compilador no le permitirá capturar la excepción en sí, aunque puede capturarla como java.lang.Salvedad.

Aquí hay una clase auxiliar que te permite lanzar cualquier cosa, declarada o no:

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

Ahora throw SneakyThrow.sneak(new ChuckNorrisException()); lanza una ChuckNorrisException, pero el compilador se queja en

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

Acerca de la captura de una excepción que es no se lanza si ChuckNorrisException es una excepción marcada.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-22 08:32:20

En realidad la respuesta aceptada no es tan agradable porque Java necesita ejecutarse sin verificación, es decir, el código no funcionaría en circunstancias normales.

AspectJ al rescate de la solución real!

Clase de excepción:

package de.scrum_master.app;

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

Aspecto:

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

Ejemplo de aplicación:

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

Salida:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-19 10:42:44

Los únicos ChuckNorrisException s en Java deben ser OutOfMemoryError y StackOverflowError.

En realidad puede "atraparlos" en el medio de que un catch(OutOfMemoryError ex) se ejecutará en caso de que se lance la excepción, pero ese bloque volverá a generar automáticamente la excepción al llamador.

No creo que public class ChuckNorrisError extends Error hace el truco, pero podría intentarlo. No he encontrado documentación sobre la extensión 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
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?

Sí, y aquí está la respuesta: Diseñe su java.lang.ChuckNorrisException de tal manera que no sea una instancia de java.lang.Throwable. ¿Por qué? Un objeto inagotable es incatchable por definición porque nunca se puede atrapar algo que nunca se puede lanzar.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-18 08:19:17

Puedes mantener a ChuckNorris interno o privado y encapsularlo o seguirlo...

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-15 04:39:23

Dos problemas fundamentales con el manejo de excepciones en Java son que utiliza el tipo de una excepción para indicar si se debe tomar una acción basada en ella, y que cualquier cosa que tome acción basada en una excepción (es decir, "catch"es it) se presume que resuelve la condición subyacente. Sería útil tener un medio por el cual un objeto de excepción podría decidir qué manejadores deben ejecutar, y si los manejadores que han ejecutado hasta ahora han limpiado las cosas lo suficiente para presente método para satisfacer sus condiciones de salida. Si bien esto podría usarse para hacer excepciones "no localizables", dos usos más grandes serían (1) hacer excepciones que solo se considerarán manejadas cuando sean capturadas por código que realmente sabe cómo manejarlas, y (2) permitir el manejo sensible de excepciones que ocurran en un bloque finally (si un FooException durante un bloque finally durante el desenrollamiento de un BarException, ambas excepciones deberían propagarse por la pila de llamadas; ambas deberían ser capturables, pero el desenrollamiento debe continuar hasta que ambos hayan sido atrapados). Desafortunadamente, no creo que haya ninguna manera de hacer que el código existente de manejo de excepciones funcione de esa manera sin romper las cosas.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-15 23:53:16

Es fácilmente posible simular una excepción no capturada en el hilo actual. Esto activará el comportamiento regular de una excepción no capturada, y por lo tanto hace el trabajo semánticamente. Sin embargo, no necesariamente detendrá la ejecución del hilo actual, ya que no se produce ninguna excepción.

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

Esto es realmente útil en situaciones (muy raras), por ejemplo cuando se requiere un manejo adecuado Error, pero el método se invoca desde un marco de trabajo que captura (y descarta) cualquier 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-09 00:37:23

Sistema de llamadas.salir (1) en el finalize, y simplemente lanzar una copia de la excepción de todos los otros métodos, de modo que el programa saldrá.

 -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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-18 01:23:38