前言
我们在实际的开发中,经常会遇到一些受检异常,我们会使用一个try-catch将其包裹在其中,如下面所示
try {
InputStream is = new FileInputStream(new File(...));
} catch(IOException e) {
// TODO
}
这样可能看不出来问题,假如我现在有多个文件需要处理,多个文件名存储在一个List中:
List<File> files = List.of(
new File("/tmp/01.txt"),
new File("/tmp/02.txt")
);
files.forEach(f -> {
try {
List<String> strings = FileUtils.readLines(f, Charset.forName("UTF-8"));
strings.forEach(System.out::println);
} catch (IOException e) {
System.out.println("抛异常了");
}
});
这样很明显了,我使用java8的forEach来迭代这个list,但是因为文件的读取会抛出一个IOException,所以我必须在forEach内部加try-catch代码块,有代码洁癖的同事看到这里会非常难受,明明我已经使用了forEach来替代丑陋的for循环了,为什么会这样呢?
解决方案
方案一——把抛异常的代码单独封装成一个方法
private static void accept(File f) {
try {
List<String> strings = FileUtils.readLines(f, Charset.forName("UTF-8"));
strings.forEach(System.out::println);
} catch (IOException e) {
System.out.println("抛异常了");
}
}
...
files.forEach(Demo02::accept);
javaslang的Try
我们可以想一下,在这个场景中,我们是否真的有必要处理IOException,文件不存在,输入输出流异常?在实际的项目中,我们可能根本不需要关注这个异常,因为发生异常的时候,肯定是数据错误或者系统错误,我们不需要关注,那这个try-catch到底是为了什么?在我看来,这就是垃圾代码,需要优化。
幸运的是,我们有了一个可以处理异常的库——javaslang(Try只是它其中一个功能),上面的diamante就可以简化成:
files.stream().map(f -> Try.of(() -> FileUtils.readLines(f, Charset.forName("UTF-8")))
.onFailure(Throwable::printStackTrace))
.filter(Try::isSuccess)
.map(Try::get)
.forEach(System.out::println);
是不是十分方便?Try有多个方法,比如onFailure可以让你在异常时执行一段代码,它还有类似Java8的流式处理的功能,非常方便。
有关javaslang的更多内容可以查看javaslang
文章评论