スローされたすべての例外がランタイム例外に自動的に変換されるように、メソッドに注釈を付ける方法はありますか?
@MagicAnnotation
// no throws clause!
void foo()
{
throw new Exception("bar")'
}
スローされたすべての例外がランタイム例外に自動的に変換されるように、メソッドに注釈を付ける方法はありますか?
@MagicAnnotation
// no throws clause!
void foo()
{
throw new Exception("bar")'
}
プロジェクトロンボク@SneakyThrows
はおそらくあなたが探しているものです。例外を実際にラップしているわけではなく(多くの場合問題になる可能性があるため)、コンパイル中にエラーをスローしません。
@SneakyThrows
void foo() {
throw new Exception("bar")'
}
AspectJ でこれを行うことができます。ジョインポイント (この場合はメソッド foo の呼び出し) を宣言し、例外を「ソフト化」します。
編集これについて少し詳しく説明するには:
次のクラスがあるとしますBar
。
public class Bar {
public void foo() throws Exception {
}
}
...そして、次のようなテストがあります:
import junit.framework.TestCase;
public class BarTest extends TestCase {
public void testTestFoo() {
new Bar().foo();
}
}
それから明らかにテストはコンパイルされません。エラーが発生します:
Unhandled exception type Exception BarTest.java(line 6)
これを AspectJ で克服するには、非常に単純なアスペクトを記述します。
public aspect SoftenExceptionsInTestCode {
pointcut inTestCode() : execution(void *Test.test*());
declare soft : Exception : inTestCode();
}
アスペクトは基本的に、AspectJ コンパイラが例外をスローするテスト (つまり、"Test" で終了し、"void" を返すクラス内の "test" で始まるメソッド) 内のすべてのコードを受け入れる必要があることを示しています。例外が発生した場合、ラップRuntimeException
され、AspectJ コンパイラによって としてスローされます。
実際、(AJDT がインストールされた) Eclipse 内から AspectJ プロジェクトの一部としてこのテストを実行すると、テストは成功しますが、アスペクトがなければコンパイルすらされません。
Checked 例外は、メソッド実装の責任です。この事実を非常に注意深く見てください。そのような回避策のアーティファクトを使用できない場合。
それを行う方法はありません。少なくとも今のところ、次のような回避策を使用しています(簡略化):
@SuppressWarnings({"rawtypes", "unchecked"})
public class Unchecked {
public static interface UncheckedDefinitions{
InputStream openStream();
String readLine();
...
}
private static Class proxyClass = Proxy.getProxyClass(Unchecked.class.getClassLoader(), UncheckedDefinitions.class);
public static UncheckedDefinitions unchecked(final Object target){
try{
return (UncheckedDefinitions) proxyClass.getConstructor(InvocationHandler.class).newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (target instanceof Class){
return MethodUtils.invokeExactStaticMethod((Class) target, method.getName(), args);
}
return MethodUtils.invokeExactMethod(target, method.getName(), args);
}
});
}
catch(Exception e){
throw new RuntimeException(e);
}
}
}
使用法は次のようになります。
import static ....Unchecked.*;
...
Writer w = ...;
unchecked(w).write(str, off, len);
秘訣は、インターフェースが「決して完成しない」ことであり、どこかで未チェックのメソッドが必要になるたびに、そのオブジェクトを未チェックにラップし、IDE にインターフェースでメソッド署名を生成させます。
実装は一般的です(反射的で「遅い」が、通常は十分に高速です)
いくつかのコード ポスト プロセッサとバイトコード ウィーバーがありますが、これは私の現在のプロジェクトでは (aop や他の jvm ベースの言語でさえ) 不可能だったので、これは「発明」されました。
バイトコードのリエンジニアリング、カスタマイズされたコンパイラ、またはおそらくアスペクト指向プログラミング1で可能だと思います。Java とは対照的に、C# には未チェックの例外しかありません2。
チェックされた例外を抑制したい理由をお聞きしてもよろしいですか?
1 Maarten Winkelsによると、これは可能です。
Channel 9 のいくつかのビデオによると、彼らはチェックされたものを導入することを考えています。
編集:質問について:メソッドに注釈を付けて、チェック例外抑制の候補になるようにフラグを立てることができるという意味で可能です。次に、コンパイル時または実行時のトリックを使用して、実際の抑制/ラッピングを適用します。
ただし、あなたのケースの環境が見えないので、これらの方法で例外をラップすると、そのメソッドのクライアントが混乱する可能性があります.RuntimeExceptionを処理する準備ができていない可能性があります. 例: メソッドは IOException をスローし、クライアントはそれを FileNotFoundException としてキャッチして、エラー ダイアログを表示します。ただし、例外を RuntimeException にラップすると、エラー ダイアログが表示されなくなり、おそらく呼び出し元のスレッドも強制終了されます。(私見では)。
Eclipse の補完/テンプレート システムを使用して、任意のコード ブロックを簡単にラップします。
ここに私のテンプレートがあります:
try { // Wrapp exceptions
${line_selection}${cursor}
} catch (RuntimeException e) { // Forward runtime exception
throw e;
} catch (Exception e) { // Wrap into runtime exception
throw new RuntimeException(
"Exception wrapped in #${enclosing_method}",
e);
}
これは、引数のないコンストラクターによってスローされたを;でラップClass.newInstance
しないという事実を使用して、どのような場合でも行うことができます。むしろそれは静かに投げます:Exception
InvocationTargetException
class ExUtil {
public static void throwSilent(Exception e) { //NOTICE NO THROWS CLAUSE
tl.set(e);
SilentThrower.class.newInstance(); //throws silently
}
private static ThreadLocal<Exception> tl = new ThreadLocal<Exception>();
private static class SilentThrower {
SilentThrower() throws Exception {
Exception e = tl.get();
tl.remove();
throw e;
}
}
}
次に、このユーティリティをどこでも使用できます。
ExUtil.throwSilent(new Exception());
//or
try {
ioMethod();
} catch (IOException e) { ExUtil.throwSilent(e); }
ちなみに、これは本当に悪い考えです:-)