抛出异常的Java 8 Lambda函数?

Java 8 Lambda function that throws exception?

我知道如何创建对具有String参数并返回int的方法的引用,它是:

1
Function<String, Integer>

但是,如果函数抛出异常,这不起作用,比如说定义为:

1
Integer myMethod(String s) throws IOException

我该如何定义这个参考?


您需要执行以下操作之一。

  • 如果它是您的代码,那么定义您自己的功能接口,声明已检查的异常:

    1
    2
    3
    4
    @FunctionalInterface
    public interface CheckedFunction<T, R> {
       R apply(T t) throws IOException;
    }

    并使用它:

    1
    void foo (CheckedFunction f) { ... }
  • 否则,在未声明已检查异常的方法中包装Integer myMethod(String s)

    1
    2
    3
    4
    5
    6
    7
    8
    public Integer myWrappedMethod(String s) {
        try {
            return myMethod(s);
        }
        catch(IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    然后:

    1
    Function<String, Integer> f = (String t) -> myWrappedMethod(t);

    要么:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    Function<String, Integer> f =
        (String t) -> {
            try {
               return myMethod(t);
            }
            catch(IOException e) {
                throw new UncheckedIOException(e);
            }
        };


实际上,您可以使用Java 8的默认方法,使用处理异常的新接口扩展Consumer(和Function等)!

考虑这个接口(extends Consumer):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@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;

}

然后,例如,如果您有一个列表:

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

如果你想使用一些抛出异常的代码来使用它(例如,用forEach),你通常会设置一个try / catch块:

1
2
3
4
5
6
7
8
9
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);

但是使用这个新接口,您可以使用lambda表达式对其进行实例化,编译器不会抱怨:

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

或者甚至只是把它变得更简洁!:

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

更新:看起来有一个非常好的Durian实用程序库部分名为Errors,它可以用来更灵活地解决这个问题。例如,在上面的实现中,我明确定义了错误处理策略(System.out...throw RuntimeException),而Durian的错误允许您通过一大套实用程序方法动态应用策略。感谢分享,@ NedTwigg!

样品用法:

1
list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));


我认为Durian的Errors类结合了上述各种建议的许多优点。

  • 将抛出函数包装到标准Java 8功能接口。
  • 轻松指定处理错误的各种策略
  • 在包装返回值的方法时,指定默认值或重新抛出RuntimeException之间存在重要区别。
  • 抛出Java 8的功能接口版本

    • 类似于fge的答案
  • 用于抛出特定异常的标准接口

    • 这解决了佐尔坦的担忧

要在项目中包含榴莲,您可以:

  • com.diffplug.durian:durian:3.3.0的jcenter或maven中心抓住它
  • 或者只是将两个小类粘贴到您的代码中:Throwing.javaErrors.java


这不是特定于Java 8.您正在尝试编译等效于:

1
2
3
4
5
6
interface I {
    void m();
}
class C implements I {
    public void m() throws Exception {} //can't compile
}


免责声明:我还没有使用过Java 8,只读过它。

Function不会抛出IOException,因此您无法在其中放入throws IOException的任何代码。如果你正在调用一个期望Function的方法,那么传递给该方法的lambda不能抛出IOException,period。你可以写这样的lambda(我认为这是lambda语法,不确定):

1
2
3
4
5
6
7
8
(String s) -> {
    try {
        return myMethod(s);
    } catch (IOException ex) {
        throw new RuntimeException(ex);
        // (Or do something else with it...)
    }
}

或者,如果您传递lambda的方法是您自己编写的方法,则可以定义新的功能接口并将其用作参数类型而不是Function

1
2
3
public interface FunctionThatThrowsIOException<I, O> {
    O apply(I input) throws IOException;
}


如果您不介意使用第三方库(Vavr),您可以写

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

它还有所谓的Try monad来处理错误:

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

请在这里阅读更多。

免责声明:我是Vavr的创始人。


你可以使用unthrow包装

1
Function<String, Integer> func1 = s -> Unthrow.wrap(() -> myMethod(s));

要么

1
Function<String, Integer> func2 = s1 -> Unthrow.wrap((s2) -> myMethod(s2), s1);

您可以。

扩展@marcg的UtilException并在必要时添加泛型:这样,编译器会强制您再次添加throw子句和所有内容,就像您可以在java 8的流上本地抛出已检查的异常一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public final class LambdaExceptionUtil {

    @FunctionalInterface
    public interface Function_WithExceptions<T, R, E extends Exception> {
        R apply(T t) throws E;
    }

    /**
     * .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName))
     */

    public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E  {
        return t -> {
            try {
                return function.apply(t);
            } catch (Exception exception) {
                throwActualException(exception);
                return null;
            }
        };
    }

    @SuppressWarnings("unchecked")
    private static <E extends Exception> void throwActualException(Exception exception) throws E {
        throw (E) exception;
    }

}

public class LambdaExceptionUtilTest {

    @Test
    public void testFunction() throws MyTestException {
        List<Integer> sizes = Stream.of("ciao","hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
        assertEquals(2, sizes.size());
        assertEquals(4, sizes.get(0).intValue());
        assertEquals(5, sizes.get(1).intValue());
    }

    private Integer transform(String value) throws MyTestException {
        if(value==null) {
            throw new MyTestException();
        }
        return value.length();
    }

    private static class MyTestException extends Exception { }
}

但是,您可以创建自己的FunctionalInterface,如下所示抛出..

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

然后使用Lambdas或引用实现它,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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");

 }

}


这里已经发布了很多很棒的回复。只是试图用不同的视角来解决问题。它只是我的2美分,请纠正我,如果我在某处错了。

FunctionalInterface中的Throws子句不是一个好主意

我认为由于以下原因,强制执行抛出IOException可能不是一个好主意

  • 这对我来说就像Stream / Lambda的反模式。整个想法是调用者将决定提供什么代码以及如何处理异常。在许多情况下,IOException可能不适用于客户端。例如,如果客户端从缓存/内存获取值而不是执行实际I / O.

  • 此外,流中的异常处理变得非常可怕。例如,如果我使用您的API,我的代码就会如此

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
               acceptMyMethod(s -> {
                    try {
                        Integer i = doSomeOperation(s);
                        return i;
                    } catch (IOException e) {
                        // try catch block because of throws clause
                        // in functional method, even though doSomeOperation
                        // might not be throwing any exception at all.
                        e.printStackTrace();
                    }
                    return null;
                });

    丑陋不是吗?而且,正如我在第一点中提到的那样,doSomeOperation方法可能会抛出IOException(取决于客户端/调用者的实现),但由于FunctionalInterface方法中的throws子句,我总是要编写试着抓。

如果我真的知道这个API会抛出IOException,我该怎么办?

  • 那么我们可能会将FunctionalInterface与典型的接口混淆。如果你知道这个API会抛出IOException,那么很可能你也知道一些默认/抽象行为。我认为您应该定义一个接口并部署您的库(使用默认/抽象实现),如下所示

    1
    2
    3
    public interface MyAmazingAPI {
        Integer myMethod(String s) throws IOException;
    }

    但是,客户端仍然存在try-catch问题。如果我在流中使用您的API,我仍然需要在hideous try-catch块中处理IOException。

  • 提供默认的流友好API,如下所示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public interface MyAmazingAPI {
        Integer myMethod(String s) throws IOException;

        default Optional<Integer> myMethod(String s, Consumer<? super Exception> exceptionConsumer) {
            try {
                return Optional.ofNullable(this.myMethod(s));
            } catch (Exception e) {
                if (exceptionConsumer != null) {
                    exceptionConsumer.accept(e);
                } else {
                    e.printStackTrace();
                }
            }

            return Optional.empty();
        }
    }

    默认方法将使用者对象作为参数,它将负责处理异常。现在,从客户的角度来看,代码将如下所示

    1
    2
    3
    strStream.map(str -> amazingAPIs.myMethod(str, Exception::printStackTrace))
                    .filter(Optional::isPresent)
                    .map(Optional::get).collect(toList());

    好吗?当然,可以使用记录器或其他处理逻辑来代替Exception :: printStackTrace。

  • 您还可以公开类似于https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptionally-java.util.function.Function-的方法。这意味着您可以公开另一个方法,该方法将包含先前方法调用的异常。缺点是你现在正在使你的API有状态,这意味着你需要处理线程安全,并最终成为性能损失。只是一个考虑的选择。


我在lambda中有Class.forName和Class.newInstance这个问题,所以我做了:

1
2
3
4
5
6
7
8
9
public Object uncheckedNewInstanceForName (String name) {

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

在lambda中,而不是调用Class.forName("myClass")。newInstance()我刚刚调用了uncheckedNewInstanceForName("myClass")


这个问题一直困扰着我;这就是我创建这个项目的原因。

有了它你可以做:

1
final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;

JDK定义了39个接口,它们具有Throwing等价物;那些都是在流中使用的@FunctionalInterface(基数Stream但也是IntStreamLongStreamDoubleStream)。

并且当它们中的每一个扩展它们的非投掷对应物时,你也可以直接在lambdas中使用它们:

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

默认行为是当您抛出lambda抛出已检查的异常时,抛出ThrownByLambdaException,并将已检查的异常作为原因。因此,您可以捕获并获得原因。

其他功能也可用。


使用Function包装器的另一个解决方案是返回结果包装器的实例,比如Success,如果一切顺利,则返回一个实例,比如Failure。

一些代码澄清事情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
public interface ThrowableFunction<A, B> {
    B apply(A a) throws Exception;
}

public abstract class Try<A> {

    public static boolean isSuccess(Try tryy) {
        return tryy instanceof Success;
    }

    public static <A, B> Function<A, Try> tryOf(ThrowableFunction<A, B> function) {
        return a -> {
            try {
                B result = function.apply(a);
                return new Success(result);
            } catch (Exception e) {
                return new Failure<>(e);
            }
        };
    }

    public abstract boolean isSuccess();

    public boolean isError() {
        return !isSuccess();
    }

    public abstract A getResult();

    public abstract Exception getError();
}

public class Success<A> extends Try<A> {

    private final A result;

    public Success(A result) {
        this.result = result;
    }

    @Override
    public boolean isSuccess() {
        return true;
    }

    @Override
    public A getResult() {
        return result;
    }

    @Override
    public Exception getError() {
        return new UnsupportedOperationException();
    }

    @Override
    public boolean equals(Object that) {
        if(!(that instanceof Success)) {
            return false;
        }
        return Objects.equal(result, ((Success) that).getResult());
    }
}

public class Failure<A> extends Try<A> {

    private final Exception exception;

    public Failure(Exception exception) {
        this.exception = exception;
    }

    @Override
    public boolean isSuccess() {
        return false;
    }

    @Override
    public A getResult() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Exception getError() {
        return exception;
    }
}

一个简单的用例:

1
2
3
List<Try<Integer>> result = Lists.newArrayList(1, 2, 3).stream().
    map(Try.<Integer, Integer>tryOf(i -> someMethodThrowingAnException(i))).
    collect(Collectors.toList());

偷偷摸摸的抛出习惯能够绕过Lambda表达式的CheckedException。在RuntimeException中包装CheckedException不利于严格的错误处理。

它可以用作Java集合中使用的Consumer函数。

这是一个简单而改进的jib答案版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
        }
    }));
}

这只是将lambda包裹在一个重新抛出中。它使CheckedException重新抛出lambda中抛出的任何Exception

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
    }

}

在这里找到完整的代码和单元测试。


您可以使用ET。 ET是一个用于异常转换/转换的小型Java 8库。

使用ET它看起来像这样:

1
2
3
4
5
6
7
8
9
10
// 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实例是线程安全的,可以由多个组件共享。如果您愿意,可以配置更具体的异常转换规则(例如FooCheckedException -> BarRuntimeException)。
如果没有其他规则可用,则已检查的异常将自动转换为RuntimeException

(免责声明:我是ET的作者)


创建将传播已检查异常的自定义返回类型。这是创建一个新接口的替代方法,该接口通过对功能接口方法的"抛出异常"的轻微修改来镜像现有的功能接口。

定义

CheckedValueSupplier

1
2
3
public static interface CheckedValueSupplier<V> {
    public V get () throws Exception;
}

为CheckedValue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class CheckedValue<V> {
    private final V v;
    private final Optional<Exception> 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<Exception> getException () {
        return opt;
    }

    public static < T > CheckedValue< T > returns (T t) {
        return new CheckedValue< T >(t);
    }

    public static < T > CheckedValue< T > rethrows (Exception e) {
        return new CheckedValue< T >(e);
    }

    public static <V> CheckedValue<V> from (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            return Result.rethrows(e);
        }
    }

    public static <V> CheckedValue<V> escalates (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//  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<String, FileReader> sToFr =
        (fn) -> new FileReader(Paths.get(fn).toFile());

// Alternative, this will compile.
    Function<String, CheckedValue<FileReader>> 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<String> paths = ...; //a list of paths to files
    Collection<CheckedValue<FileReader>> 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();

这是怎么回事?

创建抛出已检查异常的单个功能接口(CheckedValueSupplier)。这将是唯一允许检查异常的功能接口。所有其他功能接口将利用CheckedValueSupplier来包装抛出已检查异常的任何代码。

CheckedValue类将保存执行抛出已检查异常的任何逻辑的结果。这可以防止已检查异常的传播,直到代码尝试访问CheckedValue实例所包含的值为止。

这种方法存在的问题。

  • 我们现在正在抛出"异常",有效地隐藏了最初抛出的特定类型。
  • 我们不知道在调用CheckedValue#get()之前发生了异常。

消费者等

某些功能接口(例如Consumer)必须以不同的方式处理,因为它们不提供返回值。

功能代替消费者

一种方法是使用函数而不是消费者,这在处理流时适用。

1
2
3
4
5
6
7
8
    List<String> 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

升级

或者,您始终可以升级到RuntimeException。还有其他答案可以涵盖从Consumer中升级已检查的异常。

不要消费。

只需避免功能接口,并使用良好的for循环。


默认情况下,Java 8 Function不允许抛出异常,并且如多个答案中所建议的那样,有很多方法可以实现它,一种方法是:

1
2
3
4
@FunctionalInterface
public interface FunctionWithException<T, R, E extends Exception> {
    R apply(T t) throws E;
}

定义为:

1
2
3
4
5
6
private FunctionWithException<String, Integer, IOException> myMethod = (str) -> {
    if ("abc".equals(str)) {
        throw new IOException();
    }
  return 1;
};

并在调用方法中添加throwstry/catch相同的异常。


我正在做的是允许用户在异常的情况下给出他实际想要的值。
所以我看起来像这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}

然后可以这样调用:

1
defaultIfThrows(child -> child.getID(), null)


如果您不介意使用第三方库,使用cyclops-react,我参与的库,您可以使用FluentFunctions API来编写

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

ofChecked接受一个jOOλCheedFunction并将软化的引用返回给标准(未经检查)的JDK java.util.function.Function。

或者,您可以通过FluentFunctions api继续使用捕获的功能!

例如,要执行您的方法,最多重试5次并记录它的状态,您可以编写

1
2
3
4
  FluentFunctions.ofChecked(this::myMethod)
                 .log(s->log.debug(s),e->log.error(e,e.getMessage())
                 .try(5,1000)
                 .apply("my param");


我是一个带有一些通用魔法的小型lib的作者,可以在任何地方抛出任何Java异常,而无需捕获它们,也不需要将它们包装到RuntimeException中。

用法:
unchecked(() -> methodThrowingCheckedException())

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class UncheckedExceptions {

    /**
     * throws {@code exception} as unchecked exception, without wrapping exception.
     *
     * @return will never return anything, return type is set to {@code exception} only to be able to write <wyn>throw unchecked(exception)</wyn>
     * @throws T {@code exception} as unchecked exception
     */

    @SuppressWarnings("unchecked")
    public static <T extends Throwable> T unchecked(Exception exception) throws T {
        throw (T) exception;
    }


    @FunctionalInterface
    public interface UncheckedFunction<R> {
        R call() throws Exception;
    }

    /**
     * Executes given function,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @return result of function
     * @see #unchecked(Exception)
     */

    public static <R> R unchecked(UncheckedFunction<R> function) {
        try {
            return function.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }


    @FunctionalInterface
    public interface UncheckedMethod {
        void call() throws Exception;
    }

    /**
     * Executes given method,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @see #unchecked(Exception)
     */

    public static void unchecked(UncheckedMethod method) {
        try {
            method.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }
}

来源:https://github.com/qoomon/unchecked-exceptions-java


一些提供的解决方案使用E的泛型参数来传递抛出的异常类型。

更进一步,而不是传递异常的类型,传入异常类型的消费者,如...

1
Consumer<E extends Exception>

您可以创建几个可重用的Consumer变体,它们将涵盖应用程序的常见异常处理需求。


我会做一些通用的事情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface Lambda {

    @FunctionalInterface
    public interface CheckedFunction< T > {

        T get() throws Exception;
    }

    public static < T > T handle(CheckedFunction< T > supplier) {
        try {
            return supplier.get();
        } catch (Exception exception) {
            throw new RuntimeException(exception);

        }
    }
}

用法:

1
 Lambda.handle(() -> method());

使用Jool Library或从JOOQjOOλ library。它不仅提供未经检查的异常处理接口,还为Seq类提供了许多有用的方法。

此外,它还包含最多16个参数的功能接口。此外,它还提供了在不同场景中使用的Tuple类。

Jool Git Link

特别是在org.jooq.lambda.fi.util.function包的库查找中。它包含来自Java-8的所有接口,并带有Checked prepended。见下文供参考: -

enter image description here


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public void frankTest() {
    int pageId= -1;

    List<Book> users= null;
    try {
        //Does Not Compile:  Object page=DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> new Portal(rw.getInt("id"),"", users.parallelStream().filter(uu -> uu.getVbid() == rw.getString("user_id")).findFirst().get(), rw.getString("name")));

        //Compiles:
        Object page= DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> {
            try {
                final Book bk= users.stream().filter(bp -> {
                    String name= null;
                    try {
                        name = rw.getString("name");
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    return bp.getTitle().equals(name);
                }).limit(1).collect(Collectors.toList()).get(0);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return new Portal(rw.getInt("id"),"", users.get(0), rw.getString("name"));
        } );
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}