想必很多人对 JAVA 中的 Exception 不会陌生, 但是我们也会碰到诸多的 Checked Exception. 而我们又不想一层层去捕获, 那么就需要想办法来忽略这些 Checked Exception.
那么何为 Checked Exception, 何为 Unchecked Exception.
所示
正如上图中所示:
Checked Exception: 指的是不能恢复, 必须要被使用者来处理的一类异常, 如果不捕获, 那么编译会报错. 例如, IOException.
Unchecked Exception: 指的是在运行时才会导致程序奔溃的异常, 编译时候并不会报错. 例如, Runtime Exception.
如果在代码中处处来处理 Checked Exception, 那么代码就会变成冗长并且可读性变差, 所以在某些情况下需要对其进行处理, 变成 Unchecked Exception.
1. try catch
最简单的方案之一就是使用 try catch 然后在捕获到 checked exception 之后抛出 Unchecked Exception.
例如:
- public DbConnection getDbConnection(String username, String password) {
- try {
- return new DbProvider().getConnect(username, password);
- } catch (IOException e) {
- throw new RuntimeException();
- }
- }
这样的处理逻辑到处都会用到, 代码也会显得冗长, 降低了可读性.
2. 一个通用的 Wrapper
可以尝试着写一个通用的 Wrapper, 统一处理类似的 Checked Exception.
我们需要把上述代码中的 new DbProvider().getConnect(username, password); 包装成一个通用的接口 RuntimeExceptionWrappable:
- public interface RuntimeExceptionWrappable<T> {
- T execute() throws IOException;
- }
接下来可以替换原有代码中的 new DbProvider().getConnect(username, password);:
- RuntimeExceptionWrappable<DbConnection> wrappable = new RuntimeExceptionWrappable<DbConnection>() {
- @Override
- public DbConnection execute() throws IOException {
- return new DbProvider().getConnect(username, password);
- }
- };
原有代码的逻辑现在就变成下面的形式:
- RuntimeExceptionWrappable<DbConnection> wrappable = new RuntimeExceptionWrappable<DbConnection>() {
- @Override
- public DbConnection execute() throws IOException {
- return new DbProvider().getConnect(username, password);
- }
- };
- try {
- return wrappable.execute();
- } catch (IOException e) {
- throw new RuntimeException();
- }
到目前为止, 我们依然没有把 try catch 去掉. 我们接着把 try catch 部分提取出来:
- public class RuntimeExceptionWrapper {
- public static <T> T wrap(RuntimeExceptionWrappable<T> wrappable) {
- try {
- return wrappable.execute();
- } catch (IOException e) {
- throw new RuntimeException();
- }
- }
- }
最后一步, 完成整个代码:
- RuntimeExceptionWrappable<DbConnection> wrappable = new RuntimeExceptionWrappable<DbConnection>() {
- @Override
- public DbConnection execute() throws IOException {
- return new DbProvider().getConnect(username, password);
- }
- };
- return RuntimeExceptionWrapper.wrap(wrappable);
到这里就可以看到, Wrapper 被抽象到独立的类中了.
3. Stream 中的 Exception
自从 JAVA8 依赖, 流处理在代码中已经变得越来越常见, 这样就不可避免的会有 Exception 出现在 Stream 流处理中.
- public class UrlHandler {
- public List<URL> getURLs() {
- return Stream.of("http://www.baidu.com", "https://www.google.com")
- .map(this:createURL)
- .collect(Collectors.toList());
- }
- private URL createURL(String url) throws MalformedURLException {
- return new URL(url);
- }
- }
上述代码是编译不通过的, 原因是 createURL 抛出了 Checked Exception. 只有对 stream 流处理进行修改, 接收 Exception 代码才能编译:
- public List<URL> getURLs() {
- return Stream.of("http://www.baidu.com", "https://www.google.com")
- .map(url -> {
- try {
- return this.createURL(url);
- } catch (MalformedURLException e) {
- throw new RuntimeException();
- }
- })
- .collect(Collectors.toList());
- }
这段代码虽然能够工作, 但是依然显得不是很优雅. 还是跟前一部分一样, 我们抽取出来一个通用的 Wrapper.
首先将 this.createURL 提取出来, 作为一个通用的接口, 由于 createURL 是一个函数, 所以接口形式如下:
- @FunctionalInterface
- public interface RuntimeWrappableFunction<T, R> {
- R apply(T t) throws Exception;
- }
接下来, 由于 map 的参数是一个函数式接口, 所以我们来完成一个消费上述函数接口的实现:
- public class RuntimeWrappableFunctionMapper {
- public static <T, R> Function<T, R> wrap(RuntimeWrappableFunction<T, R> wrappableFunction) {
- return t -> {
- try {
- return wrappableFunction.apply(t);
- } catch (Exception e) {
- throw new RuntimeException();
- }
- };
- }
- }
完善原有的代码:
- public class UrlHandler {
- public List<URL> getURLs() {
- return Stream.of("http://www.baidu.com", "https://www.google.com")
- .map(RuntimeWrappableFunctionMapper.wrap(this::createURL))
- .collect(Collectors.toList());
- }
- private URL createURL(String url) throws MalformedURLException {
- return new URL(url);
- }
- }
有一些可选的库也可以完成上述的功能.
来源: http://www.jianshu.com/p/fe7198e2d635