不可捕捉的ChuckNorrisException
是否有可能构build一个Java代码片段,使假设的java.lang.ChuckNorrisException
不可捕捉?
想到的想法是使用拦截器或面向方面的编程 。
我没有尝试过,所以我不知道如果JVM会限制这样的东西,但也许你可以编译引发ChuckNorrisException
代码,但是在运行时提供了一个ChuckNorrisException
类的定义,它不扩展Throwable 。
更新:
它不起作用。 它会产生一个validation错误:
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:
其实,如果你禁用字节码validation器,你可以得到这个工作! ( -Xverify:none
)
更新3:
对于那些在家后面的人,这里是完整的脚本:
创build以下类:
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
跑:
java -cp . TestVillain Gotcha! The end.
注释掉“extends RuntimeException”并仅重新编译ChuckNorrisException.java
:
javac -cp . ChuckNorrisException.java
跑:
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.
无需validation即可运行
java -Xverify:none -cp . TestVillain The end. Exception in thread "main"
经过思考,我已经成功地创build了一个不可捕捉的exception。 然而,我selectJulesWinnfield
来命名,而不是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"); } }
Et瞧! 未捕获的exception。
输出:
跑:
再说一遍! 我赌你! 我量你不敢!
Java结果:8
build立成功(总时间: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) { } }
导致堆栈溢出 – 再次,exception保持未捕获。
有了这样的例外,显然必须使用System.exit(Integer.MIN_VALUE);
从构造函数,因为这是如果你抛出这样的exception会发生什么;)
任何代码都可以捕获Throwable。 所以不,不pipe你创build的exception是Throwable的一个子类,都会被捕获。
public class ChuckNorrisException extends Exception { public ChuckNorrisException() { System.exit(1); } }
(从技术上讲,这个exception事实上并没有抛出,但恰当的ChuckNorrisException
不能被抛出 – 它首先抛出你。)
你抛出的任何exception都必须扩展Throwable,所以它总是可以被捕获的。 所以答案是否定的。
如果你想使它难以处理,你可以重写方法getCause(), getMessage()
, getStackTrace()
, toString()
来抛出另一个java.lang.ChuckNorrisException
。
我的回答是基于@ 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); } }
现在去Expendables
类来构build它:
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
class级踢了一些屁股:
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
毫不奇怪 – 毕竟这是一个圆桌球:)
在构造函数中,你可以启动一个线程,反复调用originalThread.stop (ChuckNorisException.this)
线程可以反复捕获exception,但会一直抛出,直到死亡。
不。所有Java中的exception都必须是java.lang.Throwable
子类,尽pipe这可能不是很好的做法,但是您可以捕获每种types的exception:
try { //Stuff } catch ( Throwable T ){ //Doesn't matter what it was, I caught it. }
有关更多信息,请参阅java.lang.Throwable文档。
如果您试图避免检查exception (必须明确处理的exception ),那么您将需要inheritanceError或RuntimeException。
Java中唯一的ChuckNorrisException
应该是OutOfMemoryError
和StackOverflowError
。
你可以实际上“捕捉”它们的意思,即catch(OutOfMemoryError ex)
将在抛出exception的情况下执行,但该块将自动重新抛出exception给调用者。
我不认为public class ChuckNorrisError extends Error
的窍门,但你可以试试看。 我没有发现有关扩展Error
文档
其实接受的答案并不是那么好,因为Java需要不经过validation才能运行,即代码在正常情况下不起作用。
AspectJ来拯救真正的解决scheme !
exception类:
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)
Is it possible to construct a snippet of code in java that would make a hypothetical java.lang.ChuckNorrisException uncatchable?
是的,这里是答案:devise你的java.lang.ChuckNorrisException
,使它不是一个java.lang.Throwable
的实例。 为什么? 根据定义,可游动的对象是无法捕捉的,因为你永远无法捕捉永远不会被抛出的东西。
这个主题的变体是令人惊讶的事实,您可以从Java代码中抛出未声明的检查exception。 由于它没有在方法签名中声明,编译器不会让你自己捕获exception,尽pipe你可以把它作为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是一个检查的exception不会抛出的exception。
你可以保持ChuckNorris内部或私人和封装他或swollow他…
try { doChuckAction(); } catch(ChuckNorrisException cne) { /*do something else*/ }
Java中exception处理的两个基本问题是,它使用exception的types来表示是否应该基于它执行操作,并且假设根据exception采取操作(即“捕捉”exception)基本的条件。 有一个方法可以让exception对象决定哪个处理程序应该执行,以及到目前为止执行的处理程序是否已经清理了足够的方法来满足其退出条件。 虽然这可以用来制造“不可捕捉”的exception,但是两个更大的用途是:(1)制造exception,只有当它们被实际知道如何处理它们的代码捕获时才被认为是被处理的,并且(2)允许为了合理地处理在finally
块中发生的exception(如果在FooException
期间的finally
块中的BarException
exception应该传播到调用堆栈;两者应该是可捕获的,但是应该继续展开直到两者都被捕获) 。 不幸的是,我不认为有什么办法可以使现有的exception处理代码在不中断的情况下工作。
很容易在当前线程上模拟未捕获的exception。 这将触发未捕获exception的正常行为,从而在语义上完成工作。 但是,它不一定会停止当前线程的执行,因为实际上不会抛出exception。
Throwable exception = /* ... */; Thread currentThread = Thread.currentThread(); Thread.UncaughtExceptionHandler uncaughtExceptionHandler = currentThread.getUncaughtExceptionHandler(); uncaughtExceptionHandler.uncaughtException(currentThread, exception); // May be reachable, depending on the uncaught exception handler.
这在(非常less见的)情况下非常有用,例如,当需要进行适当的Error
处理时,该方法是从捕获(并丢弃)任何Throwable
的框架中调用的。
在finalize
调用System.exit(1),并从其他所有方法中抛出一个exception副本,以便程序退出。
在末尾添加一个throw子句。 这是一个很大的风险,因为没有人抛出查克·诺里斯! =)