Warum kann ich in einem Java 8-Lambda-Ausdruck keine Ausnahme auslösen?


Answers

Sie können Ausnahmen in Lambdas werfen.

Ein Lambda darf dieselben Ausnahmen wie die vom Lambda implementierte funktionale Schnittstelle auslösen.

Wenn die Methode der funktionalen Schnittstelle keine throws-Klausel hat, kann das Lambda CheckedExceptions nicht auslösen. (Sie können weiterhin RuntimeExceptions auslösen).

In Ihrem speziellen Fall verwendet Map.forEach einen BiConsumer als Parameter, BiConsumer ist definiert als:

public interface BiConsumer<T, U> {
    void accept(T t, U u);
}

Ein Lambda-Ausdruck für diese funktionale Schnittstelle kann CheckedExceptions nicht auslösen.

Die Methoden in den funktionalen Schnittstellen, die im Paket java.util.function definiert sind, java.util.function keine Ausnahmen aus, aber Sie können andere funktionale Schnittstellen verwenden oder Ihre eigenen erstellen, um Ausnahmen auslösen zu können, dh über diese Schnittstelle:

public interface MyFunctionalInterface<T> {
    void accept(T t) throws Exception;
}

Der folgende Code wäre legal:

MyFunctionalInterface<String> f = (s)->throw new Exception("Exception thrown in lambda"); 
Question

Diese Frage hat hier bereits eine Antwort:

Ich habe auf Java 8 aktualisiert und versucht, eine einfache Iteration durch eine Map mit einem neuen lamdba-Ausdruck zu ersetzen. Die Schleife sucht nach Nullwerten und löst eine Ausnahme aus, wenn eine gefunden wird. Der alte Java 7 Code sieht so aus:

for (Map.Entry<String, String> entry : myMap.entrySet()) {
    if(entry.getValue() == null) {
        throw new MyException("Key '" + entry.getKey() + "' not found!");
    }
}

Und mein Versuch, dies in Java 8 umzuwandeln, sieht so aus:

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!");
    }
});

Kann jemand erklären, warum die throw Anweisung hier nicht erlaubt ist und wie dies korrigiert werden könnte?

Der Quick-Fix-Vorschlag von Eclipse sieht für mich nicht richtig aus ... Er umgibt einfach die throw Anweisung mit einem try-catch Block:

myMap.forEach((k,v) -> {
    if(v == null) {
        try {
            throw new MyException("Key '" + k + "' not found!");
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
});