Java 8 Lambda function that throws exception?

后端 未结 26 1732
臣服心动
臣服心动 2020-11-22 03:14

I know how to create a reference to a method that has a String parameter and returns an int, it\'s:

Function         


        
26条回答
  •  [愿得一人]
    2020-11-22 03:34

    Create a custom return type that will propagate the checked exception. This is an alternative to creating a new interface that mirrors the existing functional interface with the slight modification of a "throws exception" on the functional interface's method.

    Definition

    CheckedValueSupplier

    public static interface CheckedValueSupplier {
        public V get () throws Exception;
    }
    

    CheckedValue

    public class CheckedValue {
        private final V v;
        private final Optional opt;
    
        public Value (V v) {
            this.v = v;
        }
    
        public Value (Exception e) {
            this.opt = Optional.of(e);
        }
    
        public V get () throws Exception {
            if (opt.isPresent()) {
                throw opt.get();
            }
            return v;
        }
    
        public Optional getException () {
            return opt;
        }
    
        public static  CheckedValue returns (T t) {
            return new CheckedValue(t);
        }
    
        public static  CheckedValue rethrows (Exception e) {
            return new CheckedValue(e);
        }
    
        public static  CheckedValue from (CheckedValueSupplier sup) {
            try {
                return CheckedValue.returns(sup.get());
            } catch (Exception e) {
                return Result.rethrows(e);
            }
        }
    
        public static  CheckedValue escalates (CheckedValueSupplier sup) {
            try {
                return CheckedValue.returns(sup.get());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
    }
    

    Usage

    //  Don't use this pattern with FileReader, it's meant to be an
    //  example.  FileReader is a Closeable resource and as such should
    //  be managed in a try-with-resources block or in another safe
    //  manner that will make sure it is closed properly.
    
    //  This will not compile as the FileReader constructor throws
    //  an IOException.
        Function sToFr =
            (fn) -> new FileReader(Paths.get(fn).toFile());
    
    // Alternative, this will compile.
        Function> sToFr = (fn) -> {
            return CheckedValue.from (
                () -> new FileReader(Paths.get("/home/" + f).toFile()));
        };
    
    // Single record usage
        // The call to get() will propagate the checked exception if it exists.
        FileReader readMe = pToFr.apply("/home/README").get();
    
    
    // List of records usage
        List paths = ...; //a list of paths to files
        Collection> frs =
            paths.stream().map(pToFr).collect(Collectors.toList());
    
    // Find out if creation of a file reader failed.
        boolean anyErrors = frs.stream()
            .filter(f -> f.getException().isPresent())
            .findAny().isPresent();
    

    What's going on?

    A single functional interface that throws a checked exception is created (CheckedValueSupplier). This will be the only functional interface which allows checked exceptions. All other functional interfaces will leverage the CheckedValueSupplier to wrap any code that throws a checked exception.

    The CheckedValue class will hold the result of executing any logic that throws a checked exception. This prevents propagation of a checked exception until the point at which code attempts to access the value that an instance of CheckedValue contains.

    The problems with this approach.

    • We are now throwing "Exception" effectively hiding the specific type originally thrown.
    • We are unaware that an exception occurred until CheckedValue#get() is called.

    Consumer et al

    Some functional interfaces (Consumer for example) must be handled in a different manner as they don't provide a return value.

    Function in lieu of Consumer

    One approach is to use a function instead of a consumer, which applies when handling streams.

        List lst = Lists.newArrayList();
    // won't compile
    lst.stream().forEach(e -> throwyMethod(e));
    // compiles
    lst.stream()
        .map(e -> CheckedValueSupplier.from(
            () -> {throwyMethod(e); return e;}))
        .filter(v -> v.getException().isPresent()); //this example may not actually run due to lazy stream behavior
    

    Escalate

    Alternatively, you can always escalate to a RuntimeException. There are other answers that cover escalation of a checked exception from within a Consumer.

    Don't consume.

    Just avoid functional interfaces all together and use a good-ole-fashioned for loop.

提交回复
热议问题