一:Unchecked Exception
Unchecked exception也叫做RuntimeException,出现RuntimeException通常是因为我们的代码有问题。RuntimeException是不需要被捕获的。也就是说如果有RuntimeException,没有捕获也可以通过编译。
但是后续的代码就不会再进行处理了。
List<Integer> integers = Arrays.asList(0,1,2,3,4,5); integers.forEach(i->{ System.out.println(1 / i); });
输出:
Exception in thread "main" java.lang.ArithmeticException: / by zero at test.testJava.Test2.lambda$main$0(Test2.java:13) at java.util.Arrays$ArrayList.forEach(Arrays.java:3880) at test.testJava.Test2.main(Test2.java:12)
用try-catch捕获后程序可以继续进行。
List<Integer> collect = Stream.of(1, 0, 3, 4, 0, 5, 6).collect(Collectors.toList()); collect.forEach(i -> { try { System.out.println(1 / i); } catch (ArithmeticException e) { log.info("不能为0:{}",i); e.printStackTrace(); } });
输出:
1 18:31:57.614 [main] ERROR test.testJava.Test2 - 不能为0:0 0 0 18:31:57.627 [main] ERROR test.testJava.Test2 - 不能为0:0 0 0 java.lang.ArithmeticException: / by zero at test.testJava.Test2.lambda$main$0(Test2.java:21) at java.util.ArrayList.forEach(ArrayList.java:1257) at test.testJava.Test2.main(Test2.java:19) java.lang.ArithmeticException: / by zero at test.testJava.Test2.lambda$main$0(Test2.java:21) at java.util.ArrayList.forEach(ArrayList.java:1257) at test.testJava.Test2.main(Test2.java:19)
简单但是破坏了lambda表达式的最佳实践。代码变得臃肿。
将try,catch移到一个wrapper方法中:
static Consumer<Integer> lambdaWrapper(Consumer<Integer> consumer) { return i -> { try { consumer.accept(i); } catch (ArithmeticException e) { log.error("Arithmetic Exception occured : " + e.getMessage()); System.err.println( "Arithmetic Exception occured : " + e.getMessage()); } }; }
使用:
List<Integer> collect = Stream.of(1, 0, 3, 4, 0, 5, 6).collect(Collectors.toList());
collect.forEach(
lambdaWrapper(i -> {
System.out.println(1 / i);
})
);
输出:
1 18:40:44.594 [main] ERROR test.testJava.Test2 - Arithmetic Exception occured : / by zero 0 0 18:40:44.600 [main] ERROR test.testJava.Test2 - Arithmetic Exception occured : / by zero 0 0 Arithmetic Exception occured : / by zero Arithmetic Exception occured : / by zero
但是上面的wrapper固定了捕获ArithmeticException,我们再将其改编成一个更通用的类:
static <T, E extends Exception> Consumer<T> consumerWrapperWithExceptionClass(Consumer<T> consumer, Class<E> clazz) { return i -> { try { consumer.accept(i); } catch (Exception ex) { try { E exCast = clazz.cast(ex); log.error("Exception occured:{},Exception的名字:{}" ,exCast.getMessage(),exCast.getClass()); System.err.println( "Exception occured : " + exCast.getMessage()); } catch (ClassCastException ccEx) { throw ex; } } }; }
使用:
List<Integer> collect = Stream.of(1, 0, 3, 4, 0, 5, 6).collect(Collectors.toList()); collect.forEach( consumerWrapperWithExceptionClass(i ->{ System.out.println(1 / i); } ,ArithmeticException.class ) );
输出:
1 18:49:52.890 [main] ERROR test.testJava.Test2 - Exception occured:/ by zero,Exception的名字:class java.lang.ArithmeticException 0 0 18:49:52.917 [main] ERROR test.testJava.Test2 - Exception occured:/ by zero,Exception的名字:class java.lang.ArithmeticException 0 0 Exception occured : / by zero Exception occured : / by zero
二:checked Exception
checked Exception是必须要处理的异常,我们还是看个例子:
static void throwIOException(Integer integer) throws IOException { }
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
integers.forEach(i -> throwIOException(i));
上面我们定义了一个方法抛出IOException,这是一个checked Exception,需要被处理,所以在下面的forEach中,程序会编译失败,因为没有处理相应的异常。
static <T> Consumer<T> consumerWrapper( ThrowingConsumer<T, Exception> throwingConsumer) { return i -> { try { throwingConsumer.accept(i); } catch (Exception ex) { throw new RuntimeException(ex); } }; }
调用:
integers.forEach(consumerWrapper(i -> throwIOException(i)));
封装异常,用来通用
static <T, E extends Exception> Consumer<T> consumerWrapperWithExceptionClass( ThrowingConsumer<T, E> throwingConsumer, Class<E> exceptionClass) { return i -> { try { throwingConsumer.accept(i); } catch (Exception ex) { try { E exCast = exceptionClass.cast(ex); System.err.println( "Exception occured : " + exCast.getMessage()); } catch (ClassCastException ccEx) { throw new RuntimeException(ex); } } }; }
调用:
integers.forEach(consumerWrapperWithExceptionClass( i -> throwIOException(i), IOException.class));
package test.testJava; /** * @FunctionalInterface 函数式接口 * 1:接口有且仅有一个抽象方法 * 2:允许定义静态方法 * 3:允许定义默认方法 * 4:允许java.lang.Object中的public方法 * 该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。 * 加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错 * * @param <T> * @param <E> */ @FunctionalInterface public interface ThrowingConsumer<T, E extends Exception> { void accept(T t) throws E; }