web-dev-qa-db-ja.com

キャッチできないChuckNorrisException

架空のJava.lang.ChuckNorrisExceptionをキャッチできないコードのスニペットを Java で作成することは可能ですか?

思いついたのは、たとえばインターセプターや アスペクト指向プログラミング を使用することです。

584
Max Charas

私はこれを試していないので、 JVM がこのような制限をするかどうかはわかりませんが、ChuckNorrisExceptionをスローするコードをコンパイルできますが、実行時にChuckNorrisExceptionのクラス定義を提供できますwhichは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: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.");
        }
    }
}

クラスのコンパイル:

javac -cp . TestVillain.Java ChuckNorrisException.Java

実行:

Java -cp . TestVillain
Gotcha!
The end.

「Extends RuntimeException」とrecompile ChuckNorrisException.Java onlyをコメントアウトします。

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.

検証なしで実行:

Java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"
308
jtahlborn

これを熟考した後、キャッチできない例外を作成しました。ただし、ChuckではなくJulesWinnfieldという名前を付けることを選択しました。これは、1つのキノコ雲配置母例外であるためです。さらに、それはあなたが念頭に置いていた正確なものではないかもしれませんが、それは確かにキャッチすることはできません。観察する:

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出来上がり!キャッチされなかった例外。

出力:

実行:

もう一度「何」と言ってください!出来ることならどうぞ!私はあなたをあえてダブル!

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

    }
}

スタックオーバーフローを引き起こします-再び、例外はキャッチされません。

115
MikeTheLiar

このような例外がある場合、コンストラクターからSystem.exit(Integer.MIN_VALUE);を使用することが明らかに必須になります。これは、このような例外をスローした場合に起こることだからです;)

85
Korgen

どのコードでもThrowableをキャッチできます。いいえ、作成した例外はThrowableのサブクラスになり、キャッチされる可能性があります。

45
Nathan Hughes
public class ChuckNorrisException extends Exception {
    public ChuckNorrisException() {
        System.exit(1);
    }
}

(許可、技術的にこの例外は実際にはスローされませんが、適切なChuckNorrisExceptionはスローできません-最初にスローされます。)

35
fluffy

スローする例外はThrowableを拡張する必要があるため、常にキャッチできます。答えはノーです。

処理を困難にする場合は、メソッドgetCause(), getMessage()getStackTrace()toString()をオーバーライドして、別のJava.lang.ChuckNorrisExceptionをスローできます。

28
mirelon

私の答えは@jtahlbornのアイデアに基づいていますが、それは完全に機能する Java プログラムであり、 JAR ファイルにパッケージ化して、お気に入りのアプリケーションサーバーにデプロイすることもできます Webアプリケーション の一部。

まず、ChuckNorrisExceptionクラスを定義して、最初からJVMをクラッシュさせないようにします(チャックは本当に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クラスを作成して構築します。

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

驚きはありません-結局、ラウンドハウスキックです:)

23
Wildfire

コンストラクターでは、originalThread.stop (ChuckNorisException.this)を繰り返し呼び出すスレッドを開始できます

スレッドは、例外を繰り返しキャッチできますが、死ぬまで例外をスローし続けます。

15
Peter Lawrey

いいえ。Javaのすべての例外はJava.lang.Throwableをサブクラス化する必要があります。良い方法ではないかもしれませんが、次のようにすべてのタイプの例外をキャッチできます。

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

詳細については、 Java.lang.Throwable のドキュメントを参照してください。

チェック済み例外 (明示的に処理する必要のあるもの)を回避しようとする場合は、ErrorまたはRuntimeExceptionをサブクラス化します。

13
VolatileDream

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)
9
kriegaex

テーマのバリアントは、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;
  }
}

これでthrow SneakyThrow.sneak(new ChuckNorrisException());はChuckNorrisExceptionをスローしますが、コンパイラは

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

chuckNorrisExceptionがチェック例外である場合にスローされない例外をキャッチすることについて。

8

Javaの唯一のChuckNorrisExceptionsは、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を設計します。どうして?スローできないオブジェクトは、スローできないものをキャッチできないため、定義上キャッチできません。

6
Thomas Eding

チャック・ノリスを社内またはプライベートに保ち、カプセル化または飲み込むことができます...

try { doChuckAction(); } catch(ChuckNorrisException cne) { /*do something else*/ }

3
Jay

Javaでの例外処理に関する2つの基本的な問題は、例外のタイプを使用して、それに基づいてアクションを実行するかどうかを示すこと、および例外に基づいてアクションを実行するもの(つまり "catch" esそれは)根本的な状態を解決すると推定されます。例外オブジェクトがどのハンドラーを実行するか、およびこれまでに実行したハンドラーが、現在のメソッドが終了条件を満たすのに十分なものをクリーンアップしたかどうかを決定できる手段があると便利です。これを使用して「キャッチできない」例外を作成することもできますが、2つの大きな用途は、(1)実際に対処方法を知っているコードによってキャッチされた場合にのみ処理されると見なされる例外を作成し、(2)許可することですfinallyブロックで発生する例外の賢明な処理のために(FooExceptionの巻き戻し中にfinallyブロック中にBarExceptionが発生した場合、両方の例外が呼び出しスタックを伝播する必要があります。 。残念ながら、既存の例外処理コードをそのように機能させる方法を、物事を壊さずに行う方法はないと思います。

3
supercat

現在のスレッドでキャッチされていない例外をシミュレートすることは簡単です。これにより、キャッチされない例外の通常の動作がトリガーされ、ジョブが意味的に完了します。ただし、実際に例外はスローされないため、必ずしも現在のスレッドの実行を停止するわけではありません。

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

これは、(非常にまれな)状況(たとえば、適切なError処理が必要であるが、メソッドがThrowableをキャッチ(および破棄)するフレームワークから呼び出される場合)で実際に役立ちます。

1
dst

finalizeでSystem.exit(1)を呼び出し、他のすべてのメソッドから例外のコピーをスローするだけで、プログラムが終了します。

0
Demi