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

Lesezeit: 3 Minuten

Warum kann ich in einem Java 8 Lambda Ausdruck keine Ausnahme auslosen
dokaspar

Ich habe auf Java 8 aktualisiert und versucht, eine einfache Iteration durch eine Map durch einen neuen Lambda-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 zu konvertieren, 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 Aussage hier nicht erlaubt und wie könnte dies korrigiert werden?

Der Quick-Fix-Vorschlag von Eclipse sieht für mich nicht richtig aus … er umgibt einfach die throw Aussage mit a try-catch Block:

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

  • Darauf gibt es eine ganz einfache Antwort: Lambda-Ausdrücke sind ein prägnantes Mittel zur Implementierung einer funktionalen Schnittstelle. Wie bei jeder anderen Art, eine Schnittstelle zu implementieren, müssen Sie sich an den Schnittstellenvertrag halten – was bedeutet, dass Sie nur die vom Zieltyp zugelassenen Ausnahmen auslösen können. Hier gibt es keine Magie.

    – Brian Götz

    9. Juni 2016 um 15:08 Uhr

1647176827 254 Warum kann ich in einem Java 8 Lambda Ausdruck keine Ausnahme auslosen
Andreas Tobilko

Sie dürfen keine geprüften Ausnahmen auslösen, da die accept(T t, U u) Methode in der java.util.function.BiConsumer<T, U> Schnittstelle deklariert keine Ausnahmen in seiner throws Klausel. Und wie Sie wissen, Map#forEach nimmt einen solchen Typ an.

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

}

Das trifft zu, wenn wir über geprüfte Ausnahmen sprechen. Aber Sie können immer noch eine ungeprüfte Ausnahme auslösen (z. B. a java.lang.IllegalArgumentException):

new HashMap<String, String>()
    .forEach((a, b) -> { throw new IllegalArgumentException(); });

  • Ich stimme dieser Antwort ziemlich zu. Das Verwirrende an den Javadocs ist die Aussage “Exceptions thrown by the action are relayed to the caller.”. Als Randbemerkung ist das Auslösen von Ausnahmen innerhalb eines Lambda sicherlich erlaubt, nur nicht in diesem speziellen Fall.

    – Micker

    9. Juni 2016 um 13:17 Uhr

  • @micker Es kann erwähnenswert sein, dass diese Aussage nur an die angehängt ist forEach Standardmitgliedsmethode der Iterable<T> Schnittstelle. Der primäre Stream/Consumer forEach dokumentiert nichts über das Verhalten von geprüften Ausnahmen (obwohl einige Schlussfolgerungen aus den Funktionssignaturen gezogen werden können).

    – Ti Strga

    16. Januar 2018 um 17:38 Uhr

  • @andrew-tobilko, danke für deine Antwort! Ich frage mich, ob wir einen ähnlichen Fall in Java Optional.ifPresentOrElse haben, wo wir auch keine geprüfte Ausnahme auslösen können.

    – hd84335

    16. Juli 2020 um 23:05 Uhr

Sie können Ausnahmen in Lambdas auslösen.

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

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


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

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

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


Die Methoden in den funktionalen Schnittstellen, die in definiert sind java.util.function -Paket löst keine Ausnahmen aus, aber Sie können andere funktionale Schnittstellen verwenden oder Ihre eigenen erstellen, um Ausnahmen auslösen zu können, dh angesichts dieser 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"); 

997760cookie-checkWarum kann ich in einem Java 8-Lambda-Ausdruck keine Ausnahme auslösen? [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy