Java 8にアップグレードし、Mapの単純な反復を新しいlamdba式に置き換えようとしました。ループはnull値を検索し、見つかった場合は例外をスローします。古いJava 7コードは次のようになります。
for (Map.Entry<String, String> entry : myMap.entrySet()) {
if(entry.getValue() == null) {
throw new MyException("Key '" + entry.getKey() + "' not found!");
}
}
そして、これをJava 8に変換する試みは次のようになります。
myMap.forEach((k,v) -> {
if(v == null) {
// OK
System.out.println("Key '" + k+ "' not found!");
// NOK! Unhandled exception type!
throw new MyException("Key '" + k + "' not found!");
}
});
誰がthrow
ステートメントがここで許可されなかったのか、そしてどのように修正できるのか説明できますか
Eclipseのクイックフィックスの提案は私には正しくありません...それは単にthrow
ステートメントをtry-catch
ブロックで囲んでいます:
myMap.forEach((k,v) -> {
if(v == null) {
try {
throw new MyException("Key '" + k + "' not found!");
}
catch (Exception e) {
e.printStackTrace();
}
}
});
Java.util.function.BiConsumer<T, U>
インターフェースの accept(T t, U u)
メソッドはthrows
節で例外を宣言しないため、チェック済み例外をスローすることはできません。そして、ご存知のように、 Map#forEach
はそのようなタイプを取ります。
public interface Map<K, V> {
default void forEach(BiConsumer<? super K, ? super V> action) { ... }
} |
|
V
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u); // <-- does throw nothing
}
これは、チェック例外について話しているときに当てはまります。ただし、未チェックの例外をスローすることはできます(例: Java.lang.IllegalArgumentException
):
new HashMap<String, String>()
.forEach((a, b) -> { throw new IllegalArgumentException(); });
ラムダで例外をスローできます。
ラムダは、ラムダによって実装された機能インターフェイスと同じ例外をスローできます。
関数型インターフェイスのメソッドにthrows句がない場合、ラムダはCheckedExceptionsをスローできません。 (まだRuntimeExceptionをスローできます)。
特定の場合、Map.forEach
はBiConsumer
をパラメーターとして使用し、BiConsumerは次のように定義されます。
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
この機能インターフェイスのラムダ式は、CheckedExceptionsをスローできません。
Java.util.function
パッケージで定義されている機能インターフェイスのメソッドは例外をスローしませんが、他の機能インターフェイスを使用するか、独自のインターフェイスを作成して例外をスローできます。
public interface MyFunctionalInterface<T> {
void accept(T t) throws Exception;
}
次のコードは合法です:
MyFunctionalInterface<String> f = (s)->throw new Exception("Exception thrown in lambda");