Search code examples
javafunctional-interface

What is the best way to create a general Exception wrapper?


Is it possible to have a general exception wrapper like this?

 public Function<?, Optional<?>> ExceptionWrapper = (? input) -> {
        try {
            return Optional.of(someAction(input));
        } catch (Exception e) {
            logger.warn(e.getMessage());
        }
        return Optional.empty();
    }; 

These ?s can be have different types, similar to Any in TS. The purpose is not repeating the same code.

It might be just a bad practice.


Solution

  • You can use a method like this:

    public static <T> Optional<T> wrappException(SupplierWithException<T> supplierThatThrowsException) {
        try {
            return Optional.of(supplierThatThrowsException.get());
        }
        catch (Exception e) {
            //logger.warn(e.getMessage()); //TODO add a real logger here
            System.err.println("logger warning: " + e.getMessage());
        }
        return Optional.empty();
    };
    

    This method gets a SupplierWithException<T> as parameter, that is then executed. Therefore you need to create the functional interface SupplierWithException<T> like this:

    @FunctionalInterface
    public interface SupplierWithException<T> {
        
        public T get() throws Exception;
    }
    

    Now the method can be used like this (assuming the method is defined in the class ExceptionWrapperUtil):

    public static void main(String[] args) {
        Optional<Integer> result1 = ExceptionWrapperUtil.wrappException(//
                //create a SupplierWithException object (as lambda expression, because it's a functional interface)
                //when the get() method is called (within the wrappException method) the calculation is started
                () -> {
                    return doCalculations(true);//will throw an exception that is logged
                });
        
        Optional<Integer> result2 = ExceptionWrapperUtil.wrappException(() -> {
            return doCalculations(false);//will succeed without an exception
        });
        
        System.out.println("result1 present: " + result1.isPresent());
        System.out.println("result2 present: " + result2.isPresent());
        System.out.println("result2: " + result2.get());
    }
    
    public static int doCalculations(boolean throwException) {
        boolean failed = throwException;//test throwing an exception
        
        //TODO do some calculations...
        int theAnswer = 42;
        
        if (failed) {
            throw new IllegalStateException("calculations failed");
        }
        
        return theAnswer;
    }
    

    The test generates the following output:

    logger warning: calculations failed
    result1 present: false
    result2 present: true
    result2: 42


    complete example code

    import java.util.Optional;
    
    public class ExceptionWrapperUtil {
        
        public static <T> Optional<T> wrappException(SupplierWithException<T> supplierThatThrowsException) {
            try {
                return Optional.of(supplierThatThrowsException.get());
            }
            catch (Exception e) {
                //logger.warn(e.getMessage()); //TODO add a real logger here
                System.err.println("logger warning: " + e.getMessage());
            }
            return Optional.empty();
        };
        
        @FunctionalInterface
        public interface SupplierWithException<T> {
            
            public T get() throws Exception;
        }
        
        public static void main(String[] args) {
            Optional<Integer> result1 = ExceptionWrapperUtil.wrappException(//
                    //create a SupplierWithException object (as lambda expression, because it's a functional interface)
                    //when the get() method is called (within the wrappException method) the calculation is started
                    () -> {
                        return doCalculations(true);//will throw an exception that is logged
                    });
            
            Optional<Integer> result2 = ExceptionWrapperUtil.wrappException(() -> {
                return doCalculations(false);//will succeed without an exception
            });
            
            System.out.println("result1 present: " + result1.isPresent());
            System.out.println("result2 present: " + result2.isPresent());
            System.out.println("result2: " + result2.get());
        }
        
        public static int doCalculations(boolean throwException) {
            boolean failed = throwException;//test throwing an exception
            
            //TODO do some calculations...
            int theAnswer = 42;
            
            if (failed) {
                throw new IllegalStateException("calculations failed");
            }
            
            return theAnswer;
        }
    }