是否有可能在Java中构造一段代码,使假设的Java .lang. chucknorrisexception无法捕获?

我想到的是使用拦截器或面向方面的编程。


当前回答

抛出的任何异常都必须扩展Throwable,因此总是可以捕获它。所以答案是否定的。

如果你想让它难以处理,你可以重写方法getCause(), getMessage(), getStackTrace(), toString()抛出另一个java.lang.ChuckNorrisException。

其他回答

Java中唯一的chucknorrisexception应该是OutOfMemoryError和StackOverflowError。

实际上,您可以“捕获”它们,这意味着在抛出异常时将执行catch(OutOfMemoryError ex),但该块将自动将异常重新抛出给调用者。

我不认为公共类ChuckNorrisError extends Error可以解决这个问题,但是你可以尝试一下。我没有找到关于扩展错误的文档

这个主题的另一个变体是,您可以从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;
  }
}

现在扔SneakyThrow。溜(新ChuckNorrisException ());抛出ChuckNorrisException,但编译器抱怨

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

如果ChuckNorrisException是一个受控异常,则捕获没有抛出的异常。

实际上,公认的答案并不是那么好,因为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)

在当前线程上模拟一个未捕获的异常是很容易的。这将触发未捕获异常的常规行为,从而在语义上完成工作。然而,它并不一定会停止当前线程的执行,因为实际上并没有抛出异常。

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

这实际上在(非常罕见的)情况下很有用,例如当需要适当的错误处理时,但该方法从捕获(并丢弃)任何Throwable的框架中调用。

我没有尝试过这个,所以我不知道JVM是否会限制这样的东西,但也许你可以编译抛出ChuckNorrisException的代码,但在运行时提供ChuckNorrisException的类定义,它不扩展Throwable。

更新:

不管用。它生成一个验证错误:

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:没有)

更新3:

对于那些在家跟随的人,这里是完整的脚本:

创建以下类:

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"