キャッチできないChuckNorrisException


596

仮説をキャッチできないようにするJavaのコードのスニペットを構築することは可能java.lang.ChuckNorrisExceptionですか?

頭に浮かんだ考えは、たとえばインターセプターやアスペクト指向プログラミングを使用しています



2
提供されたリンク@jschoenからの提案(バイトコードベリファイアを無効にする)を使用すると、Throwableを拡張しないものをスローできます。以下の私の答えに記載されています。
jtahlborn

4
このaioobeの回答からの抜粋は、@ jschoenが適切にリンクされている質問を要約したものです。「つまり、あなたの質問は、「JVMが仕様から逸脱している場合、プリミティブをスローするなどの奇妙なことを行うことができますか?」はい。"
ダンはFirelightによって

2
@Max-これの実用的な用途について詳しく説明できますか?
Vineet Bhatia

3
自分自身を再スローする例外はfinalize()どうですか?
Lie Ryan

回答:


314

場合、私は知らないので、私は、これを試していない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.

更新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」をコメントアウトして、再コンパイル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.

検証なしで実行:

java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"

18
Objectでは、ではなくをキャッチした場合はどうなるでしょThrowableうか。(コンパイラーはそれを許可しませんが、ベリファイアをすでに無効にしているので、バイトコードをハックしてそれを行うことができます。)
Ilmari Karonen

11
Javaでスローできるもの」によると、スロー可能を拡張しないものを引き続きキャッチできますが、それらをスローしてキャッチすることは未定義の動作です。
VolatileDream

8
@dzieciou彼らは一緒に本当であることができます。お使いのプロセッサタイプのオペレーティングシステムの特定のバージョンで、Java環境のバージョンを使用してそれらをキャッチできる場合があります。ただし、キャッチできるかどうかが標準で指定されていない場合、未定義の動作と呼ばれます。これは、Javaの他の実装がキャッチできないようにすることを選択しているためです。
heinrich5991

2
ふん。176回の賛成投票で、コールスタック全体にモンキーパッチを適用して例外を再スローする(もちろん、Actorによって呼び出されます)いくつかのJNIコードを記述してほしいと思いました。
kdgregory 2013年

3
これをすべて行うときは、片方の脚に立ち、頭を軽くたたいておなかをこすりながらディクシーを口笛で吹くのも良い考えです...;);)
Glen Best

120

これについて熟考した後、私はキャッチできない例外を作成しました。JulesWinnfieldただし、キノコの雲の敷設、母の例外の1つであるため、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

成功したビルド(合計時間: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)
    {

    }
}

スタックオーバーフローを引き起こします-ここでも、例外は捕捉されません。


32
回答でスタックオーバーフローを使用するための+1。冗談です、本当に良い答えです。
ジョサイア

7
適切な「キャッチできない例外」は、すべての囲んでいるfinallyブロックが、間にあるキャッチなしで実行されることを保証します。システムを強制終了しても例外はスローされません。システムを強制終了するだけです。
スーパーキャット

4
どうやって「投げる」のJulesWinfield?システムは、スローされる前にきしむような停止になりませんか?
supercat

6
@mikeTheLiar:コンストラクターの実行中にシステムは終了しますか?ステートメントthrow new Whatever()は実際には2つの部分で構成されています。Whatever it = new Whatever(); throw it;システムは2番目の部分に到達する前にシステムが停止します。
supercat、

5
@mikeTheLiarは、ジュールやヴィンセントを実際に簡単に捕まえることができます。それはあなたが投げることができないという例外を作成するのは簡単です:class cn extends exception{private cn(){}}
ジョン・ドヴォルザーク

85

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


32
+1; IMOこれが唯一の可能な解決策です。キャッチできない例外は、プログラムを終了する必要があります...
ホーム

7
いいえ、そのような例外をスローしても何も起こりません。キャッチされない例外は単一のスレッドを終了し、jvmを終了しません。一部のコンテキストでは、System.exit自体がSecurityExceptionを引き起こすことさえあります。すべてのコードがプログラムをシャットダウンできるわけではありません。
josefx

3
while(true){}代わりに使用できますSystem.exit()
Piotr Praszmo

2
実際には、それを許可しないセキュリティマネージャをインストールすることで、作業防ぐことができますSystem.exit()。これにより、コンストラクターが別の例外(SecurityException)に変わり、キャッチできます。
jtahlborn 2012

5
ええと、技術的には例外を投げたことありません。スローするオブジェクトをまだ作成していません!
Thomas Eding、

46

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


11
Throwableはhang、ChuckNorrisException:P
PermGenError

35
public class ChuckNorrisException extends Exception {
    public ChuckNorrisException() {
        System.exit(1);
    }
}

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


4
私の同僚は、「System.exit(1)」の呼び出しがセキュリティ例外をスローする可能性があると感じたため、「for(;;){}」を続けることを提案しました。私はこれを創造性のために投票します!
Phil Street

私はあなたの答えの終わりに同意します。ChuckNorrisやExceptionをいじらないでください。
ベンジ

28

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

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


2
うーん、catch(Throwable t)はメソッドを呼び出すか、オブジェクトを変更しますか?そのため、catch句にさらに例外をスローさせて不可能にすることもできます。
コルトン

1
私はcatch(Throwable t)それを変数に保存するだけだと思うので、私の提案は、ユーザーが例外に対処したいときに次のブロックにのみ適用されます
mirelon

24

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

最初にChuckNorrisException、最初からJVMをクラッシュさせないようにクラスを定義しましょう(チャックは本当に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);
    }
}

今度は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

驚きではありません-それは結局のところ大振りのキックです:)


非常に素晴らしい!自分でクラス定義を操作することはあまりしていません。コマンドラインで「verify:none」がまだ必要ですか?
jtahlborn

@jtahlbornはい、Throwableの子孫でないオブジェクトをスローしようとすると、「verify:none」がなければ失敗します。
Wildfire、

ああ、なんとなくこの制約を回避した印象を受けました。これは私の答えとどう違うのですか?
jtahlborn

2
主な違いは、コンパイル時のハッキングなしで動作するJavaコードであることです
Wildfire、

15

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

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


13

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

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

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

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


9

実際には、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)

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

throw SneakyThrow.sneak(new ChuckNorrisException());はChuckNorrisExceptionをスローしますが、コンパイラは不平を言います

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

ChuckNorrisExceptionがチェック済み例外である場合にスローされない例外のキャッチについて。


6

ChuckNorrisExceptionJava の唯一のはとである必要がOutOfMemoryErrorありStackOverflowErrorます。

catch(OutOfMemoryError ex)例外がスローされた場合にa が実行されるという意味で実際にそれらを「キャッチ」できますが、そのブロックは例外を呼び出し元に自動的に再スローします。

私はそれでうまくいくとは思いませんpublic class ChuckNorrisError extends Errorが、あなたはそれを試すことができます。拡張に関するドキュメントは見つかりませんでしたError


2
エラーは引き続きThrowableを拡張するため、それをキャッチすることを防ぐ方法はありません。これは、Java言語の仕様によるものです。
JasonM1

1
@ JasonM1 OPが実際には「キャッチできない」例外を要求したとは思わない。キャッチしてもエラーが伝播することを意味した。だから、どんなのThrowableが捕捉可能であるが、これらの二つは、最終的にはあなたが何をすべきかに関係なく伝播します
USR-ローカルΕΨΗΕΛΩΝ

トリッキーであるために、ChuckNorrisExceptionはThrowableを直接拡張することができ、それは例外でもエラーでもありません!
JasonM1

4
エラーがないではない、あなたがそのアイデアを得たところ、あなたがそれをキャッチした場合でも、私はよく分からない伝播します。
jtahlborn 2012

3
私はあなたがErrosについてよく混乱していると思います、それらはThrowable自体、またはThrowable自体を拡張するすべてのもののような通常の例外です。
bestss

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。どうして?スローできないオブジェクトは、スローすることができないものをキャッチすることができないため、定義によりキャッチできません。


2
しかし、それは例外ではありません。
dolbi

8
@dolbi:OPの質問の中でjava.lang.ChuckNorrisException、例外は例外であるということは言うまでもなく、投げることはできない
Thomas Eding

1
私はそれが述べられていないと思いますが、それは暗示されています。あなたは数学者です:-)、ね?
dolbi 2012

3

あなたはChuckNorrisを内部またはプライベートに保ち、彼をカプセル化するか、彼を飲み込むことができます...

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


7
私はそれを捕まえるという考えではなかったと思います。引っ掛からないようにするのが目的だと思います。
Patrick Roberts、

私が間違っている場合は修正してください。しかし、それを内部にすると、反射せずにそれに到達することはできません。
ジェイ

5
はい、ただし、ExceptionまたはThrowableをキャッチできる限り、実際の型の可視性は関係ありません。
KeithS

3

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


興味深いアイデアですが、低レベルのコードが特定の例外が呼び出し元に「意味する」ことを知っているとは思わないので、スローアーがどのハンドラーを実行するかを決定することが意味をなさないと思います。
jtahlborn 2012

@jtahlborn:現在、スローアーは、例外タイプの選択を介して、どの例外ハンドラーを実行するかを決定します。これにより、一部のシナリオを適切に処理することがほぼ不可能になります。とりわけ、(1)finallyブロックが前の例外からクリーンアップしているときに例外が発生した場合、どちらか一方の例外が、もう一方の例外がない場合、コードが処理して続行すると予期されるものである可能性が高いです。しかし、一方を処理して他方を無視するのは悪いことです。ただし、両方のハンドラが処理する複合例外を生成するメカニズムはありません。
スーパーキャット2012

@jtahlborn:また、コールバック内で発生した例外を外部アプリケーション層で処理できるようにすることが非常に難しくなります。コールバックの例外が別の例外タイプにラップされている場合、それをキャッチするかどうかを決定する際に、コールバック例外のタイプを外側のレイヤーで使用することはできません。ラップされていない場合、「偶発的な」中間層例外は、コールバックで発生するものと間違われる可能性があります。ラップされた例外オブジェクトが外部アプリケーション層に渡されたときに通知された場合は、ラップされた例外のタイプへの応答を開始できます。
スーパーキャット

私はあなたの他の点について議論していませんでした、どのハンドラーを実行するかを決定する例外オブジェクトに関するステートメントだけです。ある程度の例外タイプはすでにそれを行っていますが、あなたはもっと動的なものを望んでいるように思えますが、私はそれに同意しませんでした。私はあなたの主な議論(あなたが横から来ているようなものです)は、できる限り多くの情報を下部でキャプチャし、上部の層にそのすべての情報を見て操作させることだと思います。この一般的な点で私はあなたに同意しますが、悪魔は詳細/実装にあります。
jtahlborn

@jtahlborn:私の意図は、仮想メソッドに特に「動的」なものを実装させることではなく、本質的に「指定されたタイプの条件を実行する必要があるか」と言うことです。しかし、私が言及するのを忘れていたのは、呼び出したコードFooが、Fooそれ自体をスローしたか、故意にそれをスローしたふりをしたい例外とFoo、それが発生したときに発生すると予期していなかった例外を区別できる手段があるはずだということです。他のメソッドを呼び出す。「チェック」例外の概念は「約」であるべきです。
スーパーキャット2012

1

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

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処理が必要であるが、メソッドがanyをキャッチ(および破棄)するフレームワークから呼び出される場合などThrowableです。


0

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.