web-dev-qa-db-ja.com

Java 8ラムダ式で例外をスローできないのはなぜですか?

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();
        }
    }
});
29
dokaspar

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(); });
45
Andrew Tobilko

ラムダで例外をスローできます。

ラムダは、ラムダによって実装された機能インターフェイスと同じ例外をスローできます。

関数型インターフェイスのメソッドにthrows句がない場合、ラムダはCheckedExceptionsをスローできません。 (まだRuntimeExceptionをスローできます)。


特定の場合、Map.forEachBiConsumerをパラメーターとして使用し、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"); 
25
David SN