Neben dem klassischen Ansatz zur Fehlerbehandlung mit Ausnahmen kann auch ein funktionaler Ansatz unterschieden werden.
Anstatt eine Ausnahme sofort auszulösen, können Sie sie lokalisieren und dann bestimmte Aktionen ausführen.
Beispielsweise verwendet die Scala-Sprache hierfür eine bestimmte Try-Klasse.
def inputStreamForURL(url: String): Try[Try[Try[InputStream]]] = parseURL(url).map { u => Try(u.openConnection()).map(conn => Try(conn.getInputStream)) }
In der Java-Welt können Sie mithilfe der Vavr-Bibliothek Fehler auch in einem funktionalen Stil behandeln.
Try.of(() -> u.openConnection()).getOrElse(other);
In Java 8 wurde die optionale Klasse hinzugefügt, um mit Nulltypen korrekter zu arbeiten. Sie können ein Objekt umbrechen, das null sein kann, und in einem funktionalen Stil können Sie sicher weiter damit arbeiten.
Um mit verschiedenen Arten von Ausnahmen zu arbeiten, können Sie eine Klasse ähnlich Optional implementieren, die auch threadsicher und nicht veränderbar ist.
public final class Expected<T, E extends Throwable> { private final T value; private final E error; private Expected() { this.value = null; this.error = null; } private Expected(T value) { this.value = Objects.requireNonNull(value); this.error = null; } private Expected(E error) { this.error = Objects.requireNonNull(error); this.value = null; } public static <T, E extends Throwable> Expected<T, E> of(T value) { return new Expected<>(value); } public static <T, E extends Throwable> Expected<T, E> of(E error) { return new Expected<>(error); } public static <T, E extends Throwable> Expected<T, E> of(Supplier<T> supplier) { try { return new Expected<>(supplier.get()); } catch (Throwable e) { return new Expected<>((E) e); } } public boolean isValue() { return value != null; } public boolean isError() { return error != null; } public T value() { return value; } public E error() { return error; } }
Um zu überprüfen, ob eine Ausnahme ausgelöst wurde oder nicht, können Sie einen einfachen Besucher schreiben.
Expected<Integer, SQLException> data = Expected.of(new SQLException()); matches(data, Expected::error, e -> out.println("get error: " + e), Expected::value, v -> out.println("get value: " + v) ); Expected<Integer, ArithmeticException> expression = Expected.of(() -> 4 / 0); matches(expression, Expected::error, e -> out.println("get error: " + e), Expected::value, v -> out.println("get value: " + v) );
public static <T, E extends Throwable> void matches(Expected<T, E> value, Function<Expected<T, E>, E> firstFunction, Consumer<E> firstBranch, Function<Expected<T, E>, T> secondFunction, Consumer<T> secondBranch) { if (value.isError()) { E arg = firstFunction.apply(value); firstBranch.accept(arg); } else { T arg = secondFunction.apply(value); secondBranch.accept(arg); } }
In C ++ 23 ist geplant, der Standardbibliothek eine ähnliche Klasse hinzuzufügen.
Eine solche Klasse könnte eine gute optionale Firma in der Standard-Java-Bibliothek darstellen. Leider können Sie im Moment, um mit Ausnahmen in einem funktionalen Stil zu arbeiten, die Vavr-Bibliothek verwenden oder Ihre eigenen Klassen in der Ähnlichkeit von Expected schreiben.
Der vollständige Quellcode der Klasse kann auf github:
link eingesehen werden.