Java 8 Lambda function that throws exception?

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

    I think Durian's Errors class combines many of the pros of the various suggestions above.

    • Wrap a throwing function to a standard Java 8 functional interface.
    • Easily specify various policies for handling errors
    • When wrapping a method that returns a value, there is an important distinction between specifying a default value or rethrowing a RuntimeException.
    • Throwing versions of Java 8's functional interfaces
      • Similar to fge's answer
    • Standard interfaces for throwing specific exceptions
      • Which addresses Zoltán's concern

    To include Durian in your project, you can either:

    • grab it from jcenter or maven central at com.diffplug.durian:durian:3.3.0
    • or just copy paste just two small classes into your code: Throwing.java and Errors.java
    0 讨论(0)
  • 2020-11-22 03:19

    You could however create your own FunctionalInterface that throws as below..

    @FunctionalInterface
    public interface UseInstance<T, X extends Throwable> {
      void accept(T instance) throws X;
    }
    

    then implement it using Lambdas or references as shown below.

    import java.io.FileWriter;
    import java.io.IOException;
    
    //lambda expressions and the execute around method (EAM) pattern to
    //manage resources
    
    public class FileWriterEAM  {
      private final FileWriter writer;
    
      private FileWriterEAM(final String fileName) throws IOException {
        writer = new FileWriter(fileName);
      }
      private void close() throws IOException {
        System.out.println("close called automatically...");
        writer.close();
      }
      public void writeStuff(final String message) throws IOException {
        writer.write(message);
      }
      //...
    
      public static void use(final String fileName, final UseInstance<FileWriterEAM, IOException> block) throws IOException {
    
        final FileWriterEAM writerEAM = new FileWriterEAM(fileName);    
        try {
          block.accept(writerEAM);
        } finally {
          writerEAM.close();
        }
      }
    
      public static void main(final String[] args) throws IOException {
    
        FileWriterEAM.use("eam.txt", writerEAM -> writerEAM.writeStuff("sweet"));
    
        FileWriterEAM.use("eam2.txt", writerEAM -> {
            writerEAM.writeStuff("how");
            writerEAM.writeStuff("sweet");      
          });
    
        FileWriterEAM.use("eam3.txt", FileWriterEAM::writeIt);     
    
      }
    
    
     void writeIt() throws IOException{
         this.writeStuff("How ");
         this.writeStuff("sweet ");
         this.writeStuff("it is");
    
     }
    
    }
    
    0 讨论(0)
  • 2020-11-22 03:20

    Sneaky throw idiom enables bypassing CheckedException of Lambda expression. Wrapping a CheckedException in a RuntimeException is not good for strict error handling.

    It can be used as a Consumer function used in a Java collection.

    Here is a simple and improved version of jib's answer.

    import static Throwing.rethrow;
    
    @Test
    public void testRethrow() {
        thrown.expect(IOException.class);
        thrown.expectMessage("i=3");
    
        Arrays.asList(1, 2, 3).forEach(rethrow(e -> {
            int i = e.intValue();
            if (i == 3) {
                throw new IOException("i=" + i);
            }
        }));
    }
    

    This just wrapps the lambda in a rethrow. It makes CheckedException rethrow any Exception that was thrown in your lambda.

    public final class Throwing {
        private Throwing() {}
    
        @Nonnull
        public static <T> Consumer<T> rethrow(@Nonnull final ThrowingConsumer<T> consumer) {
            return consumer;
        }
    
        /**
         * The compiler sees the signature with the throws T inferred to a RuntimeException type, so it
         * allows the unchecked exception to propagate.
         * 
         * http://www.baeldung.com/java-sneaky-throws
         */
        @SuppressWarnings("unchecked")
        @Nonnull
        public static <E extends Throwable> void sneakyThrow(@Nonnull Throwable ex) throws E {
            throw (E) ex;
        }
    
    }
    

    Find a complete code and unit tests here.

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

    If you don't mind to use a 3rd party lib (Vavr) you could write

    CheckedFunction1<String, Integer> f = this::myMethod;
    

    It also has the so-called Try monad which handles errors:

    Try(() -> f.apply("test")) // results in a Success(Integer) or Failure(Throwable)
            .map(i -> ...) // only executed on Success
            ...
    

    Please read more here.

    Disclaimer: I'm the creator of Vavr.

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

    Use Jool Library or say jOOλ library from JOOQ. It not only provides unchecked exception handled interfaces but also provides Seq class with lots of useful methods.

    Also, it contains Functional Interfaces with up to 16 parameters. Also, it provides Tuple class which is used in different scenarios.

    Jool Git Link

    Specifically in library lookup for org.jooq.lambda.fi.util.function package. It contains all the Interfaces from Java-8 with Checked prepended. See below for reference:-

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

    This problem has been bothering me as well; this is why I have created this project.

    With it you can do:

    final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;
    

    There are a totla of 39 interfaces defined by the JDK which have such a Throwing equivalent; those are all @FunctionalInterfaces used in streams (the base Stream but also IntStream, LongStream and DoubleStream).

    And as each of them extend their non throwing counterpart, you can directly use them in lambdas as well:

    myStringStream.map(f) // <-- works
    

    The default behavior is that when your throwing lambda throws a checked exception, a ThrownByLambdaException is thrown with the checked exception as the cause. You can therefore capture that and get the cause.

    Other features are available as well.

    0 讨论(0)
提交回复
热议问题