架空のキャッチ不能になるコードのスニペットをJavajava.lang.ChuckNorrisException
で構築することは可能ですか?
頭に浮かんだ考えは、たとえばインターセプターやアスペクト指向プログラミングを使用しています。
架空のキャッチ不能になるコードのスニペットをJavajava.lang.ChuckNorrisException
で構築することは可能ですか?
頭に浮かんだ考えは、たとえばインターセプターやアスペクト指向プログラミングを使用しています。
私はこれを試したことがないので、 JVMがこのようなものを制限するかどうかはわかりませんが、スローするコードをコンパイルできますが、実行時にThrowableを拡張しないChuckNorrisException
クラス定義を提供しChuckNorrisException
ます。
アップデート:
動作しません。ベリファイアエラーが生成されます。
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.
「extendsRuntimeException」をコメントアウトし、再コンパイル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"
これを熟考した後、私はキャッチできない例外を正常に作成しました。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");
}
}
出来上がり!捕捉されなかった例外。
出力:
走る:
もう一度「何」と言ってください!出来ることならどうぞ!私はあなたを二重に敢えてします!
Javaの結果:8
BUILD SUCCESSFUL(合計時間: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)
{
}
}
スタックオーバーフローを引き起こします-繰り返しますが、例外はキャッチされないままです。
そのような例外を除いて、コンストラクターからaを使用することは明らかに必須System.exit(Integer.MIN_VALUE);
です。これは、そのような例外をスローした場合に発生するためです;)
どのコードでもThrowableをキャッチできます。したがって、作成する例外はすべてThrowableのサブクラスになり、キャッチされる可能性があります。
public class ChuckNorrisException extends Exception {
public ChuckNorrisException() {
System.exit(1);
}
}
(確かに、技術的には、この例外が実際にスローされることはありませんが、適切なChuckNorrisException
ものをスローすることはできません。最初にスローされます。)
スローする例外はすべてThrowableを拡張する必要があるため、常にキャッチできます。だから答えはノーです。
処理を困難にしたい場合は、メソッドをオーバーライドしてgetCause(), getMessage()
、別のをスローすることができます。getStackTrace()
toString()
java.lang.ChuckNorrisException
私の答えは@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
当然のことながら、それは結局のところ回し蹴りです:)
コンストラクターでは、繰り返し呼び出すスレッドを開始できますoriginalThread.stop (ChuckNorisException.this)
スレッドは例外を繰り返しキャッチできますが、終了するまで例外をスローし続けます。
いいえ。Javaのすべての例外はサブクラス化する必要java.lang.Throwable
があります。これは良い習慣ではないかもしれませんが、次のようにあらゆる種類の例外をキャッチできます。
try {
//Stuff
} catch ( Throwable T ){
//Doesn't matter what it was, I caught it.
}
詳細については、java.lang.Throwableのドキュメントを参照してください。
チェックされた例外(明示的に処理する必要がある例外)を回避しようとしている場合は、ErrorまたはRuntimeExceptionをサブクラス化する必要があります。
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)
テーマのバリエーションは、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;
}
}
ChuckNorrisExceptionthrow SneakyThrow.sneak(new ChuckNorrisException());
をスローしますが、コンパイラは次のように文句を言います。
try {
throw SneakyThrow.sneak(new ChuckNorrisException());
} catch (ChuckNorrisException e) {
}
ChuckNorrisExceptionがチェックされた例外である場合にスローされない例外をキャッチすることについて。
ChuckNorrisException
Javaの唯一のsはとである必要がOutOfMemoryError
ありStackOverflowError
ます。
実際には、例外がスローされた場合にaが実行されるという意味でそれらを「キャッチ」できますが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
。なんで?スローできないオブジェクトは、スローできないものをキャッチできないため、定義上、キャッチできません。
ChuckNorrisを内部または非公開にして、カプセル化するか、膨らませることができます...
try { doChuckAction(); } catch(ChuckNorrisException cne) { /*do something else*/ }
Javaでの例外処理に関する2つの基本的な問題は、例外のタイプを使用して、それに基づいてアクションを実行する必要があるかどうかを示すことと、例外に基づいてアクションを実行する(つまり、それを「キャッチ」する)ものはすべて解決すると推定されることです。根本的な状態。例外オブジェクトがどのハンドラーを実行するかを決定できる手段があれば便利です。また、これまでに実行したハンドラーが、現在のメソッドが終了条件を満たすのに十分なクリーンアップを行っているかどうかを判断できます。これは「キャッチできない」例外を作成するために使用できますが、2つの大きな使用法は、(1)実際にそれらを処理する方法を知っているコードによってキャッチされた場合にのみ処理されると見なされる例外を作成することです。finally
FooException
の巻き戻し中のfinally
ブロック中にBarException
、両方の例外がコールスタックに伝播する必要があります。両方ともキャッチ可能である必要がありますが、両方がキャッチされるまで巻き戻しを続ける必要があります)。残念ながら、既存の例外処理コードを壊すことなくそのように機能させる方法はないと思います。
現在のスレッドでキャッチされていない例外をシミュレートすることは簡単に可能です。これにより、キャッチされない例外の通常の動作がトリガーされ、セマンティックにジョブが実行されます。ただし、実際には例外がスローされないため、必ずしも現在のスレッドの実行が停止するわけではありません。
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
。
でSystem.exit(1)を呼び出しfinalize
、他のすべてのメソッドから例外のコピーをスローするだけで、プログラムが終了します。