647 Stimmen

Java 8 Lambda-Funktion, die eine Ausnahme wirft?

Ich weiß, wie man eine Referenz auf eine Methode erstellt, die einen String-Parameter hat und einen int zurückgibt, es ist:

Function

Allerdings funktioniert das nicht, wenn die Funktion eine Ausnahme wirft, sagen wir, sie ist definiert als:

Integer myMethod(String s) throws IOException

Wie würde ich diese Referenz definieren?

571voto

jason Punkte 227577

Sie müssen eine der folgenden Optionen auswählen.

  • Wenn es Ihr Code ist, definieren Sie Ihr eigenes funktionales Interface, das die überprüfte Ausnahme deklariert:

    @FunctionalInterface
    public interface CheckedFunction {
       R apply(T t) throws IOException;
    }

    und verwenden Sie es:

    void foo (CheckedFunction f) { ... }
  • Andernfalls wickeln Sie Integer myMethod(String s) in einer Methode ein, die keine überprüfte Ausnahme deklariert:

    public Integer myWrappedMethod(String s) {
        try {
            return myMethod(s);
        }
        catch(IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    und dann:

    Function f = (String t) -> myWrappedMethod(t);

    oder:

    Function f =
        (String t) -> {
            try {
               return myMethod(t);
            }
            catch(IOException e) {
                throw new UncheckedIOException(e);
            }
        };

256voto

jlb Punkte 17760

Sie können tatsächlich Consumer (und Function usw.) mit einer neuen Schnittstelle erweitern, die Ausnahmen behandelt - unter Verwendung von Java 8's Default-Methoden!

Betrachten Sie diese Schnittstelle (erweitert Consumer):

 @FunctionalInterface
public interface ThrowingConsumer extends Consumer {

    @Override
    default void accept(final T elem) {
        try {
            acceptThrows(elem);
        } catch (final Exception e) {
            // Implementieren Sie hier Ihre eigene Ausnahmeverarbeitungslogik..
            // Zum Beispiel:
            System.out.println("eine Ausnahme behandeln...");
            // Oder ...
            throw new RuntimeException(e);
        }
    }

    void acceptThrows(T elem) throws Exception;

}

Dann, zum Beispiel, wenn Sie eine Liste haben:

final List liste = Arrays.asList("A", "B", "C");

Wenn Sie sie konsumieren möchten (z.B. mit forEach) mit etwas Code, der Ausnahmen wirft, hätten Sie traditionell einen try/catch-Block eingerichtet:

final Consumer verbraucher = aps -> {
    try {
        // vielleicht hier noch etwas anderer Code...
        throw new Exception("asdas");
    } catch (final Exception ex) {
        System.out.println("eine Ausnahme behandeln...");
    }
};
list.forEach(verbraucher);

Aber mit dieser neuen Schnittstelle können Sie sie mit einem Lambda-Ausdruck instanziieren und der Compiler wird nicht klagen:

final ThrowingConsumer werfer = aps -> {
    // vielleicht hier noch etwas anderer Code...
    throw new Exception("asdas");
};
liste.forEach(werfer);

Oder einfach nur es zu konvertieren, um prägnanter zu sein!:

liste.forEach((ThrowingConsumer) aps -> {
    // vielleicht hier noch etwas anderer Code...
    throw new Exception("asda");
});

Update

Sieht so aus, als gäbe es eine sehr schöne Hilfsbibliothek namens Durian mit einem Teil namens Fehler, die verwendet werden kann, um dieses Problem mit wesentlich mehr Flexibilität zu lösen. Zum Beispiel habe ich in meiner obigen Implementierung die Fehlerbehandlungsrichtlinie explizit definiert (System.out... oder throw RuntimeException), während Durians Errors Ihnen ermöglichen, eine Richtlinie über eine große Auswahl an Hilfsmethoden anzuwenden. Vielen Dank fürs Teilen, @NedTwigg!.

Beispielhafte Verwendung:

liste.forEach(Errors.rethrow().wrap(c -> etwasWasAusnahmenWirft(c)));

69voto

Ned Twigg Punkte 2091

Ich denke, dass die Klasse Durian's Errors viele der Vorteile der verschiedenen oben genannten Vorschläge kombiniert.

Um Durian in Ihr Projekt einzubinden, können Sie entweder:

33voto

assylias Punkte 308529

Dies ist nicht spezifisch für Java 8. Sie versuchen, etwas Äquivalentes zu kompilieren:

Schnittstelle I {
    void m();
}
Klasse C implementiert I {
    public void m() wirft Ausnahme {} // kann nicht kompiliert werden
}

14voto

Adam R. Nelson Punkte 541

Haftungsausschluss: Ich habe Java 8 noch nicht verwendet, nur darüber gelesen.

Function wirft keine IOException, sodass Sie keinen Code darin platzieren können, der IOException wirft. Wenn Sie eine Methode aufrufen, die eine Function erwartet, dann darf das Lambda, das Sie an diese Methode übergeben, nicht IOException werfen. Sie können entweder ein Lambda wie dieses schreiben (ich denke, das ist die Lambda-Syntax, bin mir aber nicht sicher):

(String s) -> {
    try {
        return myMethod(s);
    } catch (IOException ex) {
        throw new RuntimeException(ex);
        // (Oder etwas anderes damit machen...)
    }
}

Oder wenn die Methode, der Sie das Lambda übergeben, eine von Ihnen selbst geschriebene Methode ist, können Sie eine neue funktionale Schnittstelle definieren und diese anstelle von Function als Parametertyp verwenden:

public interface FunctionThatThrowsIOException {
    O apply(I input) throws IOException;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X