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?

4voto

Arpit Aggarwal Punkte 24466

Standardmäßig erlaubt Java 8 Function nicht, eine Ausnahme zu werfen, und wie in mehreren Antworten vorgeschlagen, gibt es viele Möglichkeiten, dies zu erreichen, eine Möglichkeit ist:

@FunctionalInterface
public interface FunctionWithException {
    R apply(T t) throws E;
}

Definiere als:

private FunctionWithException myMethod = (str) -> {
    if ("abc".equals(str)) {
        throw new IOException();
    }
  return 1;
};

Und füge im Aufrufermethode throws oder try/catch die gleiche Ausnahme hinzu.

4voto

fge Punkte 115782

Dieses Problem hat mich auch gestört; deshalb habe ich dieses Projekt erstellt.

Damit kannst du folgendes machen:

final ThrowingFunction f = deineMethodenreferenzHier;

Es gibt insgesamt 39 von der JDK definierte Schnittstellen, die ein äquivalentes Throwing haben; diese sind alle @FunctionalInterfaces, die in Streams verwendet werden (der Basistyp Stream aber auch IntStream, LongStream und DoubleStream).

Und da jede von ihnen ihre nicht werfende Gegenstück erweitern, können Sie sie auch direkt in Lambdas verwenden:

myStringStream.map(f) // funktioniert

Das Standardverhalten besteht darin, dass wenn Ihre werfende Lambda eine geprüfte Ausnahme wirft, eine ThrownByLambdaException mit der geprüften Ausnahme als Ursache geworfen wird. Sie können diese also erfassen und die Ursache erhalten.

Weitere Funktionen stehen ebenfalls zur Verfügung.

4voto

Stephen Paul Punkte 33841

Ich verwende eine überladene Hilfsfunktion namens unchecked(), die verschiedene Anwendungsfälle behandelt.


EINIGE BEISPIELVERWENDUNGEN

unchecked(() -> new File("hello.txt").createNewFile());

boolean fileWasCreated = unchecked(() -> new File("hello.txt").createNewFile());

myFiles.forEach(unchecked(file -> new File(file.path).createNewFile()));

UNTERSTÜTZENDE HILFSWERKZEUGE

public class UncheckedUtils {

    @FunctionalInterface
    public interface ThrowingConsumer {
        void accept(T t) throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingSupplier {
        T get() throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingRunnable {
        void run() throws Exception;
    }

    public static <T> Consumer<T> unchecked(
            ThrowingConsumer<T> throwingConsumer
    ) {
        return i -> {
            try {
                throwingConsumer.accept(i);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        };
    }

    public static <T> T unchecked(
            ThrowingSupplier<T> throwingSupplier
    ) {
        try {
            return throwingSupplier.get();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static void unchecked(
            ThrowingRunnable throwing
    ) {
        try {
            throwing.run();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

3voto

John McClean Punkte 5017

Wenn Sie nichts dagegen haben, eine Bibliothek von Drittanbietern zu verwenden, können Sie mit cyclops-react, einer Bibliothek, zu der ich beitrage, die FluentFunctions API verwenden, um zu schreiben

 Function standardFn = FluentFunctions.ofChecked(this::myMethod);

ofChecked nimmt eine jOO CheckedFunction und gibt die Referenz wieder als eine standardmäßige (ungeprüfte) JDK java.util.function.Function zurück.

Alternativ können Sie weiterhin mit der erfassten Funktion über die FluentFunctions-API arbeiten!

Zum Beispiel, um Ihre Methode auszuführen, sie bis zu 5 Mal zu wiederholen und den Status zu protokollieren, können Sie schreiben

  FluentFunctions.ofChecked(this::myMethod)
                 .log(s->log.debug(s),e->log.error(e,e.getMessage())
                 .try(5,1000)
                 .apply("my param");

3voto

micha Punkte 45016

Sie können hierfür ET verwenden. ET ist eine kleine Java-8-Bibliothek für die Umwandlung/Übersetzung von Ausnahmen.

Mit ET sieht es so aus:

// Machen Sie dies einmal
ExceptionTranslator et = ET.newConfiguration().done();

...

// wenn Ihre Methode etwas zurückgibt
Function f = (t) -> et.withReturningTranslation(() -> myMethod(t));

// wenn Ihre Methode nichts zurückgibt
Consumer c = (t) -> et.withTranslation(() -> myMethod(t));

ExceptionTranslator-Instanzen sind threadsicher und können von mehreren Komponenten gemeinsam genutzt werden. Sie können auch spezifischere Regeln für die Umwandlung von Ausnahmen konfigurieren (z. B. FooCheckedException -> BarRuntimeException), wenn Sie möchten. Falls keine anderen Regeln verfügbar sind, werden überprüfte Ausnahmen automatisch in RuntimeException umgewandelt.

(Haftungsausschluss: Ich bin der Autor von ET)

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