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

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


当前回答

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

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的框架中调用。

其他回答

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

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的框架中调用。

在构造函数中,可以启动一个反复调用originalThread的线程。停止(ChuckNorisException.this)

线程可以重复捕获异常,但会一直抛出异常,直到异常死亡。

经过思考,我成功地创建了一个不可捕捉的异常。然而,我选择取名为JulesWinnfield,而不是Chuck,因为这是一个蘑菇云的母亲例外。此外,它可能不是你想要的,但它肯定不会被捕捉到。观察:

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

果不其然!未捕获异常。

输出:

运行: 再说一遍“什么”!我敢打赌!我真不敢相信你! Java结果:8 BUILD SUCCESSFUL(总时间: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)
    {
        
    }
}

导致堆栈溢出-同样,异常仍然未捕获。

我的答案是基于@jtahlborn的想法,但它是一个完全可用的Java程序,可以打包到JAR文件中,甚至可以作为web应用程序的一部分部署到您最喜欢的应用服务器上。

首先,让我们定义ChuckNorrisException类,这样它就不会从一开始就崩溃JVM(顺便说一句,Chuck真的很喜欢崩溃JVM:)

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

现在让敢死队来构建它:

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

这并不奇怪,毕竟这是一个回旋踢:)

不。Java中的所有异常都必须成为Java .lang的子类。虽然这可能不是一个好的实践,但你可以像这样捕获每种类型的异常:

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

有关更多信息,请参阅java.lang.Throwable文档。

如果您试图避免检查异常(必须显式处理的异常),那么您将希望继承Error或RuntimeException类。