这个UtilException helper类允许你在Java流中使用任何受控异常,如下所示:
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
注意:Class::forName抛出ClassNotFoundException,该异常被检查。流本身也会抛出ClassNotFoundException和NOT一些未检查的包装异常。
public final class UtilException {
@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; }
}
许多其他关于如何使用它的例子(在静态导入UtilException之后):
@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");
}
但在了解以下优点、缺点和限制之前,不要使用它:
•如果调用代码要处理检查异常,则必须将其添加到包含流的方法的throws子句中。
编译器不会强迫你再添加它,所以更容易忘记它。
•如果调用代码已经处理了检查异常,编译器会提醒你将throws子句添加到方法声明中
包含流(如果你不这样做,它会说:异常永远不会在相应的try语句体中抛出)。
•在任何情况下,你都不能环绕流本身来捕获包含流的方法内部的检查异常
(如果你尝试,编译器会说:异常永远不会在相应的try语句体中抛出)。
•如果你调用的方法字面上永远不会抛出它声明的异常,那么你不应该包含throws子句。
例如:new String(byteArr, "UTF-8")抛出UnsupportedEncodingException,但Java规范保证UTF-8始终存在。
在这里,throws声明是一个麻烦,任何用最少的样板文件来消除它的解决方案都是受欢迎的。
•如果你讨厌受控异常,觉得它们从一开始就不应该被添加到Java语言中(越来越多的人这样认为,
并且我不是其中之一),那么就不要将检查异常添加到包含流的方法的throws子句中。的检查
异常的行为就像一个未检查的异常。
• If you are implementing a strict interface where you don't have the option for adding a throws declaration, and yet throwing an exception is
entirely appropriate, then wrapping an exception just to gain the privilege of throwing it results in a stacktrace with spurious exceptions which
contribute no information about what actually went wrong. A good example is Runnable.run(), which does not throw any checked exceptions.
In this case, you may decide not to add the checked exception to the throws clause of the method that contains the stream.
•在任何情况下,如果你决定不添加(或忘记添加)checked异常到包含流的方法的throws子句中,
注意抛出CHECKED异常的两个后果:
1)调用代码将无法通过名称捕获它(如果你尝试,编译器会说:异常永远不会在相应的try体中抛出
声明)。它会冒泡,并可能在主程序循环中被一些“catch Exception”或“catch Throwable”捕获,这可能是你
希望无论如何。
2)它违反了最小意外原则:仅仅捕获RuntimeException就不足以保证捕获所有的RuntimeException
可能的例外。因此,我认为这不应该在框架代码中完成,而应该在您完全控制的业务代码中完成。
总之:我认为这里的限制并不严重,可以放心使用UtilException类。然而,这取决于你!
引用:
http://www.philandstuff.com/2012/04/28/sneakily-throwing-checked-exceptions.html
http://www.mail-archive.com/javaposse@googlegroups.com/msg05984.html
Project Lombok注释:@SneakyThrows
Brian Goetz的观点(反对):我如何在Java 8流中抛出CHECKED异常?
https://softwareengineering.stackexchange.com/questions/225931/workaround-for-java-checked-exceptions?newreg=ddf0dd15e8174af8ba52e091cf85688e *