此帮助程序类允许您在 Java 流中使用任何已检查的异常,如下所示:LambdaExceptionUtil
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
注意抛出 ,已选中。流本身也抛出 ,而不是一些包装未经检查的异常。Class::forName
ClassNotFoundException
ClassNotFoundException
public final class LambdaExceptionUtil {
@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
void accept(T t) throws E;
}
@FunctionalInterface
public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
void accept(T t, U u) throws E;
}
@FunctionalInterface
public interface Function_WithExceptions<T, R, E extends Exception> {
R apply(T t) throws E;
}
@FunctionalInterface
public interface Supplier_WithExceptions<T, E extends Exception> {
T get() throws E;
}
@FunctionalInterface
public interface Runnable_WithExceptions<E extends Exception> {
void run() throws E;
}
/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
return t -> {
try { consumer.accept(t); }
catch (Exception exception) { throwAsUnchecked(exception); }
};
}
public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
return (t, u) -> {
try { biConsumer.accept(t, u); }
catch (Exception exception) { throwAsUnchecked(exception); }
};
}
/** .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) { throwAsUnchecked(exception); return null; }
};
}
/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */
public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
return () -> {
try { return function.get(); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
};
}
/** uncheck(() -> Class.forName("xxx")); */
public static void uncheck(Runnable_WithExceptions t)
{
try { t.run(); }
catch (Exception exception) { throwAsUnchecked(exception); }
}
/** uncheck(() -> Class.forName("xxx")); */
public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
{
try { return supplier.get(); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
}
/** uncheck(Class::forName, "xxx"); */
public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
try { return function.apply(t); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
}
@SuppressWarnings ("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E { throw (E)exception; }
}
关于如何使用它的许多其他示例(静态导入后):LambdaExceptionUtil
@Test
public void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.forEach(rethrowConsumer(System.out::println));
}
@Test
public void test_Function_with_checked_exceptions() throws ClassNotFoundException {
List<Class> classes1
= Stream.of("Object", "Integer", "String")
.map(rethrowFunction(className -> Class.forName("java.lang." + className)))
.collect(Collectors.toList());
List<Class> classes2
= Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
}
@Test
public void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
Collector.of(
rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
}
@Test
public void test_uncheck_exception_thrown_by_method() {
Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));
Class clazz2 = uncheck(Class::forName, "java.lang.String");
}
@Test (expected = ClassNotFoundException.class)
public void test_if_correct_exception_is_still_thrown_by_method() {
Class clazz3 = uncheck(Class::forName, "INVALID");
}
截至2015年11月更新在@PaoloC的帮助下,代码得到了改进,请检查下面的答案并投赞成票。他帮助解决了最后一个问题:现在编译器会要求你添加 throw 子句,一切都好像你可以在 Java 8 流上原生地抛出已检查的异常。
附注 1上述类的方法可以毫无畏惧地使用,并且可以在任何情况下使用。rethrow
LambdaExceptionUtil
注2:上述类的方法是奖励方法,如果您不想使用它们,可以安全地从类中删除它们。如果您确实使用了它们,请小心行事,而不是在了解以下用例,优点/缺点和限制之前:uncheck
LambdaExceptionUtil
• 如果您调用的方法实际上永远不会引发它所声明的异常,则可以使用这些方法。例如:new String(byteArr, “UTF-8”) 抛出 UnsupportedEncodingException,但 Java 规范保证 UTF-8 始终存在。在这里,throws声明是一种麻烦,任何用最小的样板来沉默它的解决方案都是受欢迎的:uncheck
String text = uncheck(() -> new String(byteArr, "UTF-8"));
• 如果您正在实现一个严格的接口,并且您无法选择添加 throws 声明,但抛出异常是完全合适的,则可以使用这些方法。包装异常只是为了获得抛出它的特权,会导致堆栈跟踪具有虚假异常,这些异常不会提供有关实际出错的信息。一个很好的例子是Runnable.run(),它不会引发任何检查的异常。uncheck
•在任何情况下,如果您决定使用这些方法,请注意在没有抛出子句的情况下抛出CHECKED异常的以下2个后果:1)调用代码将无法按名称捕获它(如果您尝试,编译器会说:异常永远不会在相应的try语句的正文中抛出)。它会冒泡,可能会被一些“catch Exception”或“catch Throwable”捕获到主程序循环中,这可能是你想要的。2)它违反了最小意外原则:它不再足以捕获,以确保捕获所有可能的异常。出于这个原因,我认为这不应该在框架代码中完成,而只能在你完全控制的业务代码中完成。uncheck
RuntimeException