[解決済み] Java 8のストリーム内部からCHECKED例外を投げるにはどうすればよいですか?
質問
Java 8 streams/lambdas 内部から CHECKED 例外を投げるにはどうしたらいいですか?
つまり、このようなコードをコンパイルできるようにしたいのです。
public List<Class> getClasses() throws ClassNotFoundException {
List<Class> classes =
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(className -> Class.forName(className))
.collect(Collectors.toList());
return classes;
}
このコードはコンパイルされません。
Class.forName()
メソッドは
ClassNotFoundException
がチェックされます。
チェックされた例外を実行時例外にラップし、ラップされたチェックされていない例外を代わりに投げることはしたくないことに注意してください。
チェックした例外そのものを投げたい
そして、醜い
try
/
catches
をストリームに送信します。
解決方法は?
これは
LambdaExceptionUtil
ヘルパークラスは、このようにJavaストリームで任意のチェックされた例外を使用できるようにします。
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
備考
Class::forName
スローズ
ClassNotFoundException
である。
チェック済み
. また、ストリーム自体も
ClassNotFoundException
という例外が発生します。
public final class LambdaExceptionUtil {
@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
void accept(T t) throws E;
}
@FunctionalInterface
public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
void accept(T t, U u) throws E;
}
@FunctionalInterface
public interface Function_WithExceptions<T, R, E extends Exception> {
R apply(T t) throws E;
}
@FunctionalInterface
public interface Supplier_WithExceptions<T, E extends Exception> {
T get() throws E;
}
@FunctionalInterface
public interface Runnable_WithExceptions<E extends Exception> {
void run() throws E;
}
/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
return t -> {
try { consumer.accept(t); }
catch (Exception exception) { throwAsUnchecked(exception); }
};
}
public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
return (t, u) -> {
try { biConsumer.accept(t, u); }
catch (Exception exception) { throwAsUnchecked(exception); }
};
}
/** .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName)) */
public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E {
return t -> {
try { return function.apply(t); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
};
}
/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */
public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
return () -> {
try { return function.get(); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
};
}
/** uncheck(() -> Class.forName("xxx")); */
public static void uncheck(Runnable_WithExceptions t)
{
try { t.run(); }
catch (Exception exception) { throwAsUnchecked(exception); }
}
/** uncheck(() -> Class.forName("xxx")); */
public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
{
try { return supplier.get(); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
}
/** uncheck(Class::forName, "xxx"); */
public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
try { return function.apply(t); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
}
@SuppressWarnings ("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E { throw (E)exception; }
}
他の多くの使用例(静的にインポートした後に
LambdaExceptionUtil
):
@Test
public void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.forEach(rethrowConsumer(System.out::println));
}
@Test
public void test_Function_with_checked_exceptions() throws ClassNotFoundException {
List<Class> classes1
= Stream.of("Object", "Integer", "String")
.map(rethrowFunction(className -> Class.forName("java.lang." + className)))
.collect(Collectors.toList());
List<Class> classes2
= Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
}
@Test
public void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
Collector.of(
rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
}
@Test
public void test_uncheck_exception_thrown_by_method() {
Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));
Class clazz2 = uncheck(Class::forName, "java.lang.String");
}
@Test (expected = ClassNotFoundException.class)
public void test_if_correct_exception_is_still_thrown_by_method() {
Class clazz3 = uncheck(Class::forName, "INVALID");
}
2015年11月時点のUPDATE パオロC(@PaoloC)氏の協力により、コードを改善しました。 以下の彼の回答を確認し、アップボートしてください。 . これで、コンパイラはthrow句を追加するように要求し、あたかもJava 8ストリームでチェックされた例外をネイティブにスローできるかのようになりました。
ノート1
は
rethrow
のメソッドを使用します。
LambdaExceptionUtil
クラスは、安心して使用できます。
どのような状況でも使用OK
.
注2.
は
uncheck
のメソッドを使用します。
LambdaExceptionUtil
クラスはボーナス・メソッドなので、使わないのであればクラスから削除してもかまいません。もし使用するのであれば、以下の使用例、利点/欠点、制限を理解した上で、慎重に行いましょう。
- を使用することができます。
uncheck
メソッドを呼び出す場合、文字通りそのメソッドが宣言している例外を投げることができない場合です。例えば、new String(byteArr, "UTF-8") throws UnsupportedEncodingException ですが、UTF-8 は Java の仕様では常に存在することが保証されているのです。ここで、throws宣言は厄介であり、最小限の定型表現でそれを黙らせるための解決策は歓迎されます。
String text = uncheck(() -> new String(byteArr, "UTF-8"));
- を使用することができます。
uncheck
もし、throws 宣言を追加できないような厳密なインターフェイスを実装していて、かつ、例外を投げることが完全に適切な場合は、throws メソッドを使用します。例外を投げる特権を得るためだけに例外をラップすると、何が実際にうまくいかなかったのかについての情報を提供しない偽の例外でスタックトレースを行う結果となります。その良い例が Runnable.run() で、これはチェックされた例外を一切投げません。
- いずれにせよ、もしあなたが
uncheck
メソッドを使用します。
throws節を付けずにCHECKED例外を投げると、以下の2つの結果に注意する必要があります。1) 呼び出し側のコードで名前を付けてキャッチできない(キャッチしようとすると、コンパイラはこう言うでしょう。例外は、対応するtry文の本体で投げられたことはありません。) これは、おそらくメインプログラムのループの中で、何らかの "catch Exception" または "catch Throwable" によって捕捉されることになるでしょう。2) 最小驚嘆の原則に違反します。
RuntimeException
を使えば、起こりうる例外をすべて捕捉することが保証されます。このため、フレームワークのコードでは行わず、自分が完全にコントロールするビジネスコードでのみ行うべきだと思います。
- リファレンス
- http://www.philandstuff.com/2012/04/28/sneakily-throwing-checked-exceptions.html
- http://www.mail-archive.com/[email protected]/msg05984.html
- Project Lombokのアノテーションです。スニーキングスロー(SneakyThrows
- Brian Goetzの意見(反対)はこちら。 Java 8のストリーム内部からCHECKED例外を投げるにはどうすればよいですか?
- https://softwareengineering.stackexchange.com/questions/225931/workaround-for-java-checked-exceptions?newreg=ddf0dd15e8174af8ba52e091cf85688e *
関連
-
このラインで複数のマーカーを解決する方法
-
[解決済み] android.os.NetworkOnMainThreadException' を修正するにはどうすればよいですか?
-
[解決済み] JavaでInputStreamを読み込んでStringに変換するにはどうすればよいですか?
-
[解決済み] Java Mapの各エントリを効率的に反復処理するには?
-
[解決済み] Javaでメモリーリークを発生させるにはどうしたらいいですか?
-
[解決済み] JavaでStringをintに変換するにはどうしたらいいですか?
-
[解決済み] Java で、あるコンストラクタを別のコンストラクタから呼び出すにはどうすればよいですか?
-
[解決済み] Javaで文字列値からenum値を取得する方法
-
[解決済み] Java 8 StreamをArrayに変換する方法は?
-
[解決済み] Javaにおけるチェック済み例外とチェックされていない例外の理解
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
コンストラクタの呼び出しは、コンストラクタのエラー理解の最初のステートメントである必要があります。
-
JavaMailのメール送信が失敗するケースとその説明の分析
-
JDKの設定時にjava.dllが見つからない、java SE Runtime Environmentが見つからない問題が発生しました。
-
JQuery DataTable 详解
-
[オリジナル】java学習ノート【II】よくあるエラー クラスパス上のクラスファイルが見つからない、またはアクセスできない場合
-
org.glassfish.jersey.servlet.ServletContainer
-
IDEA パッケージステートメントの欠落
-
[解決済み] Java 8 Iterable.forEach() vs foreachループ
-
[解決済み】Java 8 Lambda関数が例外を投げる?
-
[解決済み] Java 8: ラムダストリーム、例外を含むメソッドによるフィルタリング