Además del enfoque clásico para manejar errores usando excepciones, también se puede distinguir un enfoque funcional.
En lugar de lanzar una excepción de inmediato, puede localizarla y luego realizar ciertas acciones en ella.
Por ejemplo, en Scala, se usa una clase Try específica para esto.
def inputStreamForURL(url: String): Try[Try[Try[InputStream]]] = parseURL(url).map { u => Try(u.openConnection()).map(conn => Try(conn.getInputStream)) }
En el mundo Java, utilizando la biblioteca Vavr, también puede manejar errores en un estilo funcional.
Try.of(() -> u.openConnection()).getOrElse(other);
En Java 8, se agregó la clase Opcional para trabajar más correctamente con tipos nulos. Le permite envolver un objeto, que puede ser nulo, y en un estilo funcional es seguro trabajar con él aún más.
Para trabajar con diferentes tipos de excepciones, puede implementar una clase similar a Opcional, que también es segura para subprocesos y no mutable.
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; } }
Además, para verificar si se produjo una excepción o no, puede escribir un simple visitante.
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); } }
En C ++ 23, se planea agregar una clase similar a la biblioteca estándar.
Dicha clase podría constituir una buena compañía opcional en la biblioteca estándar de Java. Pero, por el momento, para trabajar con excepciones en un estilo funcional, puede usar la biblioteca Vavr o escribir sus propias clases a semejanza de lo esperado.
El código fuente completo de la clase se puede ver en github:
link .