From 023cc940331caffe6710691f16fcca92e6ad5bfa Mon Sep 17 00:00:00 2001 From: Ben Culkin Date: Sat, 21 Nov 2020 11:09:20 -0500 Subject: Add a functional interface for functions that throw an exception. This allows you to be able to throw one type of checked exception from a normal function It also has some methods to allow you to attempt to recover from an exception and hide the fact that it was thrown --- src/main/java/bjc/functypes/ThrowFunction.java | 88 ++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/main/java/bjc/functypes/ThrowFunction.java (limited to 'src/main/java') diff --git a/src/main/java/bjc/functypes/ThrowFunction.java b/src/main/java/bjc/functypes/ThrowFunction.java new file mode 100644 index 0000000..b72d735 --- /dev/null +++ b/src/main/java/bjc/functypes/ThrowFunction.java @@ -0,0 +1,88 @@ +package bjc.functypes; + +import java.util.function.*; + +/** + * An instance of {@link Function} that can throw an exception. + * + * @author Ben Culkin + * + * @param The input to the function. + * @param The output to the function. + * @param The type of exception thrown. + */ +public interface ThrowFunction { + /** + * Does the possibly throwing computation embodied by this function. + * + * @param arg The input to the function. + * + * @return The result of the function. + * + * @throws ExType If something went wrong with the function. + */ + public ReturnType apply(InputType arg) throws ExType; + + /** + * Converts this into a {@link Function} by handling any thrown exceptions. + * + * @param clasz The class of the handled exception. This needs to be provided + * because you can't catch a generic exception, and we want to + * make sure that we aren't catching any types of exception that + * we aren't supposed to. + * + * @param handler The handler to use. + * + * @return A function which will either return its proper value, or the result + * of invoking the handler. + */ + @SuppressWarnings("unchecked") + default Function swallow( + Class clasz, Function handler) { + return (inp) -> { + try { + return this.apply(inp); + } catch (Throwable ex) { + if (clasz.isInstance(ex)) { + // Swallow this + return handler.apply((ExType) ex); + } else { + String msg = "Exception of incorrect type to be handled, only " + + clasz.getName() + + " are handled"; + + throw new RuntimeException(msg, ex); + } + } + }; + } + + /** + * Convert this to a function which will attempt to recover from the thrown exception. + * + * @param clasz The class of the exception. Needed for type-safety reasons. + * @param rescue The function to use to convert an exception into a safe input value. + * + * @return A function which attempts to recover from a exception. + */ + @SuppressWarnings("unchecked") + default Function recover( + Class clasz, BiFunction rescue) { + return Fixpoints.fix((arg, self) -> { + try { + return this.apply(arg); + } catch (Throwable ex) { + if (clasz.isInstance(ex)) { + // Swallow this + return self.apply(rescue.apply(arg, (ExType) ex)); + } else { + String msg = "Exception of incorrect type to be handled, only " + + clasz.getName() + + " are handled"; + + throw new RuntimeException(msg, ex); + } + } + }); + } +} -- cgit v1.2.3