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)
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)
导致堆栈溢出 - 再次,异常仍未被捕获.
Kor*_*gen 85
有了这样的例外,显然必须使用System.exit(Integer.MIN_VALUE);构造函数中的a ,因为如果你抛出这样的异常会发生这种情况;)
Nat*_*hes 46
任何代码都可以捕获Throwable.所以不,你创建的任何异常都将成为Throwable的子类,并且会被捕获.
flu*_*ffy 35
public class ChuckNorrisException extends Exception {
public ChuckNorrisException() {
System.exit(1);
}
}
Run Code Online (Sandbox Code Playgroud)
(当然,从技术上讲,这个例外实际上从未被抛出,但是ChuckNorrisException不能抛出正确的- 它会先抛出你.)
mir*_*lon 28
您抛出的任何异常都必须扩展Throwable,因此可以始终捕获它.所以答案是否定的.
如果你想使它难以处理,你可以重写方法getCause(), getMessage(),getStackTrace(),toString()抛出另一个java.lang.ChuckNorrisException.
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)
毫不奇怪 - 毕竟这是一个圆屋顶踢:)
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.
实际上接受的答案并不是那么好,因为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)
主题的变体是令人惊讶的事实,即您可以从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是一个已检查的异常,则捕获未抛出的异常.
ChuckNorrisExceptionJava中唯一的应该是OutOfMemoryError和StackOverflowError.
实际上,你可以catch(OutOfMemoryError ex)在抛出异常的情况下"捕获"它们,但是该块会自动将异常重新抛出给调用者.
我不认为这public class ChuckNorrisError extends Error是诀窍,但你可以尝试一下.我找不到有关扩展的文档Error
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.为什么?根据定义,无法捕获的对象是无法捕捉的,因为你永远无法捕获永远不会抛出的东西.