Java 8 Lambda function that throws exception?

后端 未结 26 1712
臣服心动
臣服心动 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:22

    If you don't mind using a third party library, with cyclops-react, a library I contribute to, you can use the FluentFunctions API to write

     Function<String, Integer> standardFn = FluentFunctions.ofChecked(this::myMethod);
    

    ofChecked takes a jOOλ CheckedFunction and returns the reference softened back to a standard (unchecked) JDK java.util.function.Function.

    Alternatively you can keep working with the captured function via the FluentFunctions api!

    For example to execute your method, retrying it up to 5 times and logging it's status you can write

      FluentFunctions.ofChecked(this::myMethod)
                     .log(s->log.debug(s),e->log.error(e,e.getMessage())
                     .try(5,1000)
                     .apply("my param");
    
    0 讨论(0)
  • 2020-11-22 03:23

    What I'm doing is to allow the user to give the value he actually want in case of exception . So I've something looking like this

    public static <T, R> Function<? super T, ? extends R> defaultIfThrows(FunctionThatThrows<? super T, ? extends R> delegate, R defaultValue) {
        return x -> {
            try {
                return delegate.apply(x);
            } catch (Throwable throwable) {
                return defaultValue;
            }
        };
    }
    
    @FunctionalInterface
    public interface FunctionThatThrows<T, R> {
        R apply(T t) throws Throwable;
    }
    

    And this can then be call like :

    defaultIfThrows(child -> child.getID(), null)
    
    0 讨论(0)
  • 2020-11-22 03:24

    I had this problem with Class.forName and Class.newInstance inside a lambda, so I just did:

    public Object uncheckedNewInstanceForName (String name) {
    
        try {
            return Class.forName(name).newInstance();
        }
        catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
    

    Inside the lambda, instead of calling Class.forName("myClass").newInstance() I just called uncheckedNewInstanceForName ("myClass")

    0 讨论(0)
  • 2020-11-22 03:25

    You can use ET for this. ET is a small Java 8 library for exception conversion/translation.

    With ET it looks like this:

    // Do this once
    ExceptionTranslator et = ET.newConfiguration().done();
    
    ...
    
    // if your method returns something
    Function<String, Integer> f = (t) -> et.withReturningTranslation(() -> myMethod(t));
    
    // if your method returns nothing
    Consumer<String> c = (t) -> et.withTranslation(() -> myMethod(t));
    

    ExceptionTranslator instances are thread safe an can be shared by multiple components. You can configure more specific exception conversion rules (e.g. FooCheckedException -> BarRuntimeException) if you like. If no other rules are available, checked exceptions are automatically converted to RuntimeException.

    (Disclaimer: I am the author of ET)

    0 讨论(0)
  • 2020-11-22 03:27

    Disclaimer: I haven't used Java 8 yet, only read about it.

    Function<String, Integer> doesn't throw IOException, so you can't put any code in it that throws IOException. If you're calling a method that expects a Function<String, Integer>, then the lambda that you pass to that method can't throw IOException, period. You can either write a lambda like this (I think this is the lambda syntax, not sure):

    (String s) -> {
        try {
            return myMethod(s);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
            // (Or do something else with it...)
        }
    }
    

    Or, if the method you're passing the lambda to is one you wrote yourself, you can define a new functional interface and use that as the parameter type instead of Function<String, Integer>:

    public interface FunctionThatThrowsIOException<I, O> {
        O apply(I input) throws IOException;
    }
    
    0 讨论(0)
  • 2020-11-22 03:28

    You can actually extend Consumer (and Function etc.) with a new interface that handles exceptions -- using Java 8's default methods!

    Consider this interface (extends Consumer):

    @FunctionalInterface
    public interface ThrowingConsumer<T> extends Consumer<T> {
    
        @Override
        default void accept(final T elem) {
            try {
                acceptThrows(elem);
            } catch (final Exception e) {
                // Implement your own exception handling logic here..
                // For example:
                System.out.println("handling an exception...");
                // Or ...
                throw new RuntimeException(e);
            }
        }
    
        void acceptThrows(T elem) throws Exception;
    
    }
    

    Then, for example, if you have a list:

    final List<String> list = Arrays.asList("A", "B", "C");
    

    If you want to consume it (eg. with forEach) with some code that throws exceptions, you would traditionally have set up a try/catch block:

    final Consumer<String> consumer = aps -> {
        try {
            // maybe some other code here...
            throw new Exception("asdas");
        } catch (final Exception ex) {
            System.out.println("handling an exception...");
        }
    };
    list.forEach(consumer);
    

    But with this new interface, you can instantiate it with a lambda expression and the compiler will not complain:

    final ThrowingConsumer<String> throwingConsumer = aps -> {
        // maybe some other code here...
        throw new Exception("asdas");
    };
    list.forEach(throwingConsumer);
    

    Or even just cast it to be more succinct!:

    list.forEach((ThrowingConsumer<String>) aps -> {
        // maybe some other code here...
        throw new Exception("asda");
    });
    

    Update: Looks like there's a very nice utility library part of Durian called Errors which can be used to solve this problem with a lot more flexibility. For example, in my implementation above I've explicitly defined the error handling policy (System.out... or throw RuntimeException), whereas Durian's Errors allow you to apply a policy on the fly via a large suite of utility methods. Thanks for sharing it, @NedTwigg!.

    Sample usage:

    list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));
    
    0 讨论(0)
提交回复
热议问题