无法捕获的ChuckNorrisException

Max*_*ras 588 java aop exception-handling exception

是否有可能在Java中构建一个代码片段,使得假设无法java.lang.ChuckNorrisException捕获?

想到的想法是使用例如拦截器或面向方面的编程.

jta*_*orn 310

我没有试过,所以我不知道,如果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.
Run Code Online (Sandbox Code Playgroud)

更新2:

实际上,如果禁用字节码验证器,您可以使用它!(-Xverify:none)

更新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.");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编译类:

javac -cp . TestVillain.java ChuckNorrisException.java
Run Code Online (Sandbox Code Playgroud)

跑:

java -cp . TestVillain
Gotcha!
The end.
Run Code Online (Sandbox Code Playgroud)

注释掉"extends RuntimeException"并重新编译ChuckNorrisException.java:

javac -cp . ChuckNorrisException.java
Run Code Online (Sandbox Code Playgroud)

跑:

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.
Run Code Online (Sandbox Code Playgroud)

运行时无需验证:

java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"
Run Code Online (Sandbox Code Playgroud)

  • 好的,那么如果你抓住`Object`而不是`Throwable`呢?(编译器不会允许它,但是因为我们已经禁用了验证器,所以可能会破解字节码来执行它.) (18认同)
  • 根据[你能用Java做什么](http://stackoverflow.com/questions/5749898/what-c​​an-you-throw-in-java),你仍然可以捕捉到不能延伸扔掉的东西,但扔掉和捕捉它们是未定义的行为. (11认同)
  • @dzieciou他们可以在一起真实.您可以在处理器类型的特定操作系统版本上使用您的Java环境版本来捕获它们.但是如果它没有在标准中指定它是否可以被捕获,那么它被称为未定义行为,因为Java的其他实现可能会选择使其不可捕获. (8认同)
  • 在做所有这一切的时候,站在一条腿上,拍拍你的头,揉搓肚子同时吹口哨dixie也是一个好主意...;);) (3认同)
  • Hmmph.我希望对于176个upvotes,你已经编写了一些JNI代码,它们修补整个调用堆栈来重新抛出你的异常(当然是由ctor调用). (2认同)
  • @kdgregory - 热切期待你的回答...... :) (2认同)

Mik*_*iar 117

在考虑了这个之后,我成功地创建了一个无法捕获的异常.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's a word for that Jules - a bum");
    }
}
Run Code Online (Sandbox Code Playgroud)

瞧瞧!未捕获的异常.

输出:

跑:

再说'什么'!我赌你!我量你不敢!

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

    }
}
Run Code Online (Sandbox Code Playgroud)

导致堆栈溢出 - 再次,异常仍未被捕获.

  • 在你的答案中使用Stack Overflow +1.开玩笑,真的很好的答案. (31认同)
  • 一个适当的"无法捕获的异常"将确保所有封闭的finally块都可以在没有任何干预捕获的情况下执行.杀死系统不会引发异常 - 它只会杀死系统. (7认同)
  • @mikeTheLiar你实际上很容易抓住朱尔斯或文森特......如果你设法扔掉它.创建一个你不能抛出的异常很容易:`class cn extends exception {private cn(){}}` (5认同)
  • 你怎么"扔"朱尔斯温菲尔德?在抛出系统之前系统是否会停止嘎嘎作响? (4认同)
  • @mikeTheLiar:系统在构造函数中退出,不是吗?声明`throw new Whatever()`实际上是两部分:`无论它=新的Whatever(); 抛出它;`,系统在到达第二部分之前就死了. (4认同)
  • 实际上,您_可以_捕获一个`stackOverflowError`。 (2认同)

Kor*_*gen 85

有了这样的例外,显然必须使用System.exit(Integer.MIN_VALUE);构造函数中的a ,因为如果你抛出这样的异常会发生这种情况;)

  • +1; IMO这是唯一可行的解​​决方案.一个无法捕获的异常应该终止该程序...... (32认同)
  • 不,当你抛出这样的异常时,它不会发生什么.未捕获的异常将终止单个线程,它不会退出jvm,在某些上下文中System.exit本身甚至会导致SecurityException - 并不是每一段代码都允许关闭程序. (7认同)
  • 嗯,从技术上讲,你从来没有*扔过一个例外.你还没有构造出要抛出的对象! (5认同)
  • 你可以使用`while(true){}`而不是`System.exit()`. (3认同)
  • 实际上,你可以通过安装一个不允许它的安全管理器来阻止`System.exit()`工作.这会将构造函数转换为可以捕获的另一个异常(SecurityException). (2认同)
  • @Hoeloe 我认为当您尝试抛出无法捕获的异常时并不重要。两者都不应该在严肃的代码中完成。 (2认同)

Nat*_*hes 46

任何代码都可以捕获Throwable.所以不,你创建的任何异常都将成为Throwable的子类,并且会被捕获.

  • 为了抓住ChuckNorrisException,Throwable会"挂起"自己:P (11认同)

flu*_*ffy 35

public class ChuckNorrisException extends Exception {
    public ChuckNorrisException() {
        System.exit(1);
    }
}
Run Code Online (Sandbox Code Playgroud)

(当然,从技术上讲,这个例外实际上从未被抛出,但是ChuckNorrisException不能抛出正确的- 它会先抛出你.)

  • 我的一位同事建议坚持'for(;;){}',因为他觉得'System.exit(1)'调用可能会引发安全例外.我正在为创造力投票! (4认同)

mir*_*lon 28

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

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

  • 嗯,catch(Throwable t)调用任何方法或以其他方式使对象变异?可能导致catch子句进一步引发异常,从而使其不可能。 (2认同)

Wil*_*ire 23

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

首先,让我们定义ChuckNorrisException类,以便它不会从一开始就崩溃JVM(Chuck真的喜欢崩溃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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后这个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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用以下命令编译并运行它:

java -Xverify:none -cp .:<path_to_javassist-3.9.0.GA.jar> chuck.Main
Run Code Online (Sandbox Code Playgroud)

您将获得以下输出:

before
finally
Run Code Online (Sandbox Code Playgroud)

毫不奇怪 - 毕竟这是一个圆屋顶踢:)

  • 主要区别在于它没有编译时黑客的java代码 (2认同)

Pet*_*rey 15

在构造函数中,您可以启动一个重复调用的线程 originalThread.stop (ChuckNorisException.this)

线程可以反复捕获异常,但会一直抛出它直到它死掉.


Vol*_*eam 13

不是.Java中的所有异常都必须是子类java.lang.Throwable,虽然它可能不是一个好习惯,但您可以捕获每种类型的异常,如下所示:

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

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

如果您试图避免检查异常(必须显式处理的异常),那么您将需要子类Error或RuntimeException.


kri*_*aex 9

实际上接受的答案并不是那么好,因为Java需要在没有验证的情况下运行,即代码在正常情况下不起作用.

AspectJ为抢救真正的解决方案!

例外类:

package de.scrum_master.app;

public class ChuckNorrisException extends RuntimeException {
    public ChuckNorrisException(String message) {
        super(message);
    }
}
Run Code Online (Sandbox Code Playgroud)

方面:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

样品申请:

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!");
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

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)
Run Code Online (Sandbox Code Playgroud)


Han*_*örr 8

主题的变体是令人惊讶的事实,即您可以从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;
  }
}
Run Code Online (Sandbox Code Playgroud)

现在throw SneakyThrow.sneak(new ChuckNorrisException());抛出一个ChuckNorrisException,但编译器抱怨

try {
  throw SneakyThrow.sneak(new ChuckNorrisException());
} catch (ChuckNorrisException e) {
}
Run Code Online (Sandbox Code Playgroud)

关于如果ChuckNorrisException是一个已检查的异常,则捕获未抛出的异常.


usr*_*ΛΩΝ 6

ChuckNorrisExceptionJava中唯一的应该是OutOfMemoryErrorStackOverflowError.

实际上,你可以catch(OutOfMemoryError ex)在抛出异常的情况下"捕获"它们,但是该块会自动将异常重新抛出给调用者.

我不认为这public class ChuckNorrisError extends Error是诀窍,但你可以尝试一下.我找不到有关扩展的文档Error

  • 错误确实_not_传播即使你抓住它,我不知道你在哪里有这个想法. (3认同)
  • [错误](http://docs.oracle.com/javase/6/docs/api/java/lang/Error.html) 仍然扩展 Throwable 所以没有办法阻止捕获它。这是 Java 语言的设计。 (2认同)
  • 我认为你对Erros很困惑,它们是正常的例外,比如延伸Throwable甚至Throwable本身. (2认同)

Tho*_*ing 6

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.为什么?根据定义,无法捕获的对象是无法捕捉的,因为你永远无法捕获永远不会抛出的东西.

  • @dolbi:我在OP的问题中找不到一个地方,即`java.lang.ChuckNorrisException`必须是一个例外,更不用说扔掉了 (8认同)
  • 但这也不例外。 (2认同)