Необязательный ChuckNorrisException

Можно ли построить фрагмент кода в Java, который сделал бы гипотетическим java.lang.ChuckNorrisException uncatchable?

Мысли, которые приходят на ум, используют, например, перехватчики или аспектно-ориентированное программирование.

Ответ 1

Я не пробовал это, поэтому я не знаю, будет ли JVM ограничивать что-то вроде этого, но, возможно, вы можете скомпилировать код который выдает ChuckNorrisException, но во время выполнения предоставляет определение класса ChuckNorrisException, которое не расширяет Throwable.

UPDATE:

Это не работает. Он генерирует ошибку верификации:

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.

ОБНОВЛЕНИЕ 2:

Собственно, вы можете заставить это работать, если вы отключите верификатор байтового кода! (-Xverify:none)

ОБНОВЛЕНИЕ 3:

Для тех, кто находится дома, вот полный script:

Создайте следующие классы:

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

Скомпилировать классы:

javac -cp . TestVillain.java ChuckNorrisException.java

Run:

java -cp . TestVillain
Gotcha!
The end.

Комментарий "extends RuntimeException" и перекомпилируйте только ChuckNorrisException.java:

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.

Запуск без проверки:

java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"

Ответ 2

Подумав об этом, я успешно создал неустранимое исключение. Однако я решил назвать его JulesWinnfield, а не Чаком, потому что это одно исключение для грибных облаков. Кроме того, это может быть не совсем то, что вы имели в виду, но это, безусловно, невозможно поймать. Обратите внимание:

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 a word for that Jules - a bum");
    }
}

Эт вуаля! Исключить исключение.

Вывод:

пробег:

Скажи "Что" снова! Попробуй! Я вам смею!

Java Результат: 8

СОЗДАТЬ УСПЕШНОЕ (общее время: 0 секунд)

Когда у меня будет немного больше времени, я посмотрю, не могу ли я придумать что-то еще.

Также проверьте это:

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

    }
}

Вызывает переполнение стека - снова исключения остаются неотображаемыми.

Ответ 3

При таком исключении, очевидно, было бы обязательно использовать конструктор System.exit(Integer.MIN_VALUE); из конструктора, потому что это произойдет, если вы выбросите такое исключение;)

Ответ 4

Любой код может захватывать Throwable. Таким образом, нет, любое исключение, которое вы создадите, будет подклассом Throwable и будет подвергнуто заражению.

Ответ 5

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

(Конечно, технически это исключение на самом деле никогда не бросается, но правильный ChuckNorrisException нельзя выбросить - он бросает вас первым.)

Ответ 6

Любое исключение, которое вы бросаете, должно расширять Throwable, поэтому его всегда можно поймать. Так что ответ - нет.

Если вы хотите, чтобы было трудно справиться, вы можете переопределить методы getCause(), getMessage(), getStackTrace(), toString(), чтобы выбросить еще один java.lang.ChuckNorrisException.

Ответ 7

Мой ответ основан на идее @jtahlborn, но это полностью работающая программа Java, которая может быть упакована в JAR и даже развернуто на ваш любимый сервер приложений в составе веб-приложения.

Прежде всего, давайте определим класс ChuckNorrisException, чтобы он не разбивал JVM с самого начала (Чак действительно любит разбивать JVMs 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);
    }
}

Теперь идет класс Expendables для его построения:

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

И, наконец, класс Main, чтобы выбить какой-то прикладом:

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

Скомпилируйте и запустите его с помощью следующей команды:

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

Вы получите следующий результат:

before
finally

Не удивительно - это крутой удар в конце концов:)

Ответ 8

В конструкторе вы можете запустить поток, который повторно вызывает originalThread.stop (ChuckNorisException.this)

Этот поток может неоднократно перехватывать исключение, но будет продолжать бросать его, пока он не умрет.

Ответ 9

Нет. Все исключения в Java должны подкласса java.lang.Throwable, и, хотя это может быть не очень хорошая практика, вы можете поймать все типы исключений, например:

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

Подробнее см. java.lang.Throwable для документации.

Если вы пытаетесь избежать проверенных исключений (те, которые должны быть явно обработаны), тогда вы захотите подкласса Error или RuntimeException.

Ответ 10

Единственный ChuckNorrisException в Java должен быть OutOfMemoryError и StackOverflowError.

Вы действительно можете "поймать" их в том, что catch(OutOfMemoryError ex) будет выполняться в случае возникновения исключения, но этот блок автоматически восстановит исключение для вызывающего.

Я не думаю, что public class ChuckNorrisError extends Error делает трюк, но вы можете попробовать. Я не нашел документации о расширении Error

Ответ 11

Вариант темы - удивительный факт, что вы можете бросить необъявленные проверенные исключения из кода Java. Поскольку он не объявлен в сигнатуре методов, компилятор не позволит вам поймать само исключение, хотя вы можете поймать его как java.lang.Exception.

Вот класс-помощник, который позволяет вам что-то выкидывать, объявить или нет:

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

Теперь throw SneakyThrow.sneak(new ChuckNorrisException()); делает бросок ChuckNorrisException, но компилятор жалуется на

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

об улавливании исключения, которое не выбрасывается, если ChuckNorrisException является проверенным исключением.

Ответ 12

На самом деле принятый ответ не так хорош, потому что Java нужно запускать без проверки, т.е. код не будет работать при нормальных обстоятельствах.

AspectJ для спасения для реального решения!

Класс исключений:

package de.scrum_master.app;

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

Формат:

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

Пример приложения:

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

Вывод:

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)

Ответ 13

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

Да, и вот ответ: Создайте свой java.lang.ChuckNorrisException так, чтобы он не был экземпляром java.lang.Throwable. Зачем? Необратимый объект нечетко по определению, потому что вы никогда не сможете поймать то, что никогда не может быть брошено.

Ответ 14

Вы можете оставить ChuckNorris внутренним или частным и инкапсулировать его или налить ему...

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

Ответ 15

Две фундаментальные проблемы с обработкой исключений в Java - это то, что он использует тип исключения, чтобы указать, следует ли принимать на нем действие, и что все, что принимает действие, основанное на исключении (т.е. "catch" ) предположительно для устранения основного условия. Было бы полезно иметь средства, с помощью которых объект исключения мог бы решить, какие обработчики должны выполнить, и выполняются ли обработчики, которые уже выполнили до сих пор, чтобы настоящий метод удовлетворял условиям выхода. Хотя это может быть использовано для создания "неуловимых" исключений, два больших использования будут заключаться в том, чтобы (1) делать исключения, которые будут считаться обработанными только тогда, когда они пойманы кодом, который действительно знает, как с ними бороться, и (2) разрешить для разумной обработки исключений, которые встречаются в блоке finally (если a FooException во время блока finally во время разматывания BarException, оба исключения должны распространяться вверх по стеку вызовов, оба должны быть захватывающими, но раскручивать должны продолжаться до тех пор, пока оба не будут пойманы). К сожалению, я не думаю, что какой-либо способ заставить существующий код обработки исключений работать таким образом, не нарушая ничего.

Ответ 16

Легко можно моделировать неперехваченное исключение в текущем потоке. Это вызовет регулярное поведение неперехваченного исключения и, таким образом, выполняет работу семантически. Однако он не обязательно остановит текущее выполнение потока, так как исключение фактически не выбрано.

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

Это действительно полезно в (очень редких) ситуациях, например, когда требуется правильная обработка Error, но метод вызывается из фреймворка, улавливающего (и отбрасывая) любой Throwable.

Ответ 17

Вызовите System.exit(1) в finalize и просто выбросите копию исключения из всех других методов, чтобы программа выходила.

Ответ 18

Добавьте предложение throw в конец. Это большой риск, потому что никто не бросает Чака Норриса! =)