如何优雅地在 Java 8 中处理异常
2019独角兽企业重金招聘Python工程师标准>>>
前言
Java 8 引入的流 (Stream) API 和 lambda 表达式为我们打开了新世界的大门,自此之后我们也可以在 Java 中进行函数式编程了。然而,在实际工作中,许多小伙伴并不知道如何正确的在 lambda 中处理异常,今天就来给大家讲解一下。
我们都知道,Java 异常分为检查异常和非检查异常。检查异常就是编译器要求开发者必须处理的异常,而非检查异常则没有这个要求。所以当我们需要调用某个抛出检查异常的方法时,必须明确捕获它:
myList.stream().map(item ->try{return doSomething(item);} catch(MyException e){throw new RuntimeException (e);}}).forEach(System.out::printion);
如上面代码所示,我们捕获了 MyException 这个检查异常,然后将其转化为 RuntimeException 非检查异常,重新抛出。但是你自己心里面其实清楚的很,这不是最好的处理方式。
优化一: 提升可读性
如下所示,我们将方法体单独提取到 trySomething 方法中,这样的话,我们就可以使用一行代码完成 lambda 表达式,整个代码可读性也会提升不少:
myList.stream().map(this::trySomething).forEach(System.out::printion);private Item trySomething(Item item) {try{return doSomething(item);} catch(MyException e){throw new RuntimeException (e);} }
优化二: 复用代码
现在你已经解决了上述的问题,然而当我们再碰到需要处理异常的其它方法时,难道我们都要用 try ... catch ... 包裹一层吗?那样的话,你可以想象代码中可能到处都是这种类似的写法。为了避免陷入到这种重复的写法中,我们应该将上述代码片段抽象为一个小的工具类,专门用来干这件事情。你只需要定义一次,然后再需要的地方多次调用它就可以了。
为了实现这个目标,我们首先需要自己定义一个函数式接口,这个接口可能会抛出一个异常:
然后,我们来写一个静态帮助函数 wrap ,该方法接受一个函数式接口参数,在方法体内捕获检查异常,并抛出非检查异常 RuntimeException:
借助于 wrap 静态函数,现在你可以在 lambda 表达式中这么写了
优化三: 出现异常时继续运行
上述代码的可读性、抽象性已经很好了,然而还存在一个比较大的问题,那就是当出现异常的时候,你的 stream 代码会立即停止,不会接着处理下一个元素。大多数情况下,当抛出异常的时候,我们可能还想让 stream 继续运行下去。
我们与其抛出异常,将异常当成一种特殊的情况处理,还不如直接将异常当成是一个 “正常” 的返回值。即这个函数要么返回一个正确的结果,要么返回一个异常,所以我们现在需要定义一个新的封装类 Either,用来存储这两种结果。为了方便,我们将异常存储到 left 这个字段中,将正常返回的值存储到 right 这个字段中。下面就是 Either 类的一个简单示例:
public class Eithercl<L,R>{private final L Left:private final R right;private Either(L left, R right){this left=left;this right =right; } public static <L, R> Either,<L,R> Left( L value) {return new Either(value, null): } public static <L, R> Either<L, R> Right( R value) {return new Either(null, value) } public Optional<L> getleft() {return Optional. ofnullable(left) } public Optional<R> getright() {return Optional.ofnullable(right); } public boolean isleft() {return left I- null; } public boolean isright(){return right != null; } public < T> optional<T> mapleft(Function<? super L, T> mapper){if (isleft()) {return Optional of(mapper. apply(left));}return Optional empty(); } public <T> Optional<T> mapright(Function<? super R, T> mapper) {if (isright()) {return Optional of(mapper. apply(right));}return Optionalempty(); } public String tostring(){if (isleft()){return"Left(”+left+")";}return "Right("+ right +")";} }
现在我们需要再定义一个 lift 函数,该函数内部将 function 函数正常返回的值或者抛出的异常都使用 Either 类进行了一层封装
现在我们的代码变成这个样子了,也不用担心方法抛出异常会提前终止 Stream 了
优化四: 保留原始值
现在思考一个问题,如果在上述处理过程中,当结果是异常信息的时候,我们想要重试,即重新调用这个方法怎么办? 你会发现我们 Either 封装类没有保存最原始的这个值,我们丢掉了原始值,因此我们可以进一步优化,将原始值 t 也封装进 left 字段中,就像下面这样:
Pair 类是一个非常简单的封装类,用以封装两个值:
public class Pair<F, S> {public final F fst;public final S snd;private Pair(F fst, S snd){this fst fst;this snd= snd;} public static <F, S> Pair<F, S> of(F fst, S snd){return new Pair<>(fst, snd);} }
这样,当我们遇见异常的时候,我们可以从 Pair 中取出最原始的值 t,无论是想重试,还是做一些其他操作,都很方便了。
小编给大家推荐一个Java后端技术群:479499375!群内提供设计模式、spring/mybatis源码分析、高并发与分布式、微服务、性能优化,面试题整合文档等免费资料!给大家提供一个交流学习的平台!
总结
我们经过上文一点一点地优化代码,得到了一个比较满意的在 Java 8 中处理异常的通用方式。其实,大家还可以关注 Github 上的有关函数式编程方面的库,比如 Javaslang ,它实现了多种多样的函数式帮助方法和封装类来帮助开发者写好 lambda 表达式。但是,如果你只是为了处理异常,而引入这么大的一个第三方库的话,就不太建议了哦~
转载于:https://my.oschina.net/u/3967312/blog/2999944
如何优雅地在 Java 8 中处理异常相关推荐
- JAVA语言异常,Java语言中的异常
1.异常分类 从产生源头来看,Java语言中的异常可以分为两类: JVM抛出的异常.比如:访问null引用会引发NullPointerException:0作为除数,如9/0,JVM会抛出Arithm ...
- java学习中,异常和错误的简介、捕获异常、抛出异常、自定义异常、finally关键字(java 学习中的小记录)
java学习中,异常和错误的简介.捕获异常.抛出异常.自定义异常.finally关键字(java 学习中的小记录) 参考文章: (1)java学习中,异常和错误的简介.捕获异常.抛出异常.自定义异常. ...
- java编程中的异常分析及面向对象的思考总结[图]
java编程中的异常分析及面向对象的思考总结[图] 1.异常: 程序中出现的不正常现象. 2.异常的由来: 程序在运行的过程中出现了不正常的情况,程序把它看成对象提取了属性行为(名字,原因,位置等信息 ...
- 解释java程序中的异常机制_Java编程中的异常机制
本文旨在以初学者的角度来学习Java异常的知识,尽量简单,一些细枝末节的知识不会讲述,但不影响对知识的掌握. (比如try-catch可以嵌套,不太会这么用) 1.什么是异常 我们先举个例子 int ...
- 八股文系列:Java中的异常和错误
Java异常架构与异常关键字 Java异常简介 Java异常是Java提供的一种识别及响应错误的一致性机制. Java异常机制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程 ...
- 关于Java中的异常,面试可以问的都在这里了!
Java异常简介 Java异常是Java提供的一种识别及响应错误的一致性机制. Java异常机制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程序健壮性.在有效使用异常的情况 ...
- java异常类型 数组越界_java数组中的异常类型整理
对于程序中出现异常,是很多程序员不想看到的情况,因为这就需要我们去查询异常的原因,然后进行一些处理异常的操作.在Java数组操作时,也会有一些异常情况的发生.这里我们罗列出了两种:ClassCastE ...
- 如何在Java 8中使用LocalDateTime格式化/解析日期-示例教程
Java项目中的常见任务之一是将日期格式化或解析为String,反之亦然. 解析日期表示您有一个表示日期的字符串,例如" 2017-08-3",并且要将其转换为表示Java中日期的 ...
- java中抛出异常快捷键_idea中处理异常的快捷键
建议68:从System.Exception或其他常见的基本异常中派生异常 微软建议:从System.Exception或其他常见基本异常之一派生异常.在Visual Studio中输入Excepti ...
最新文章
- 高通 android平台LCD驱动分析
- 中国健康体检行业行情动态及未来发展趋向分析报告2022年版
- mysql Insert on duplicate引发的死锁
- centos下安装pip时失败:
- 通过源码理解反射与注解是什么东西?
- hdf5文件-环境配置/使用读写
- 初学者求经典java学习视频
- 小白入,告诉你.ssh新建config文件究竟是哪种文件!
- CreatePipe 函数
- Amazon Dynamo论文中文版
- 电动汽车续航标准傻傻分不清楚?别再被车企的等速续航骗了!
- 已知多边形各顶点坐标如何计算多边形面积
- python读取以及保存gif图
- Java编程入门与应用 P104—例4-12(学生管理系统——密码的重复验证)
- windows 屏幕键盘路径
- 爬取大众点评数据的血泪史
- 【2016 下半年总结】 拨开云雾见天日——专注提升自己最重要
- (一百零四)探讨WiFi分析仪如何获取信道的?
- 高盛合伙人制度和激励机制
- 拼多多想制作出优质的主图?需了解这六点!
热门文章
- mybatis整合ehcache
- php设计模式 - 建造者模式
- OCS2007R2部署之一软硬件环境准备
- svcagent32.exe,javaM.exe木马查杀解决方案 (转Ad0.cn)
- 怎么用python判断数据是否已经存在于表里_数据基本操作(二)
- python requests max retries_我可以为request.request设置max_retries吗?
- 利用Python绘制萌萌哒的皮卡丘
- 都啥时候了,你还怕学了Python找不到工作?
- 最强python技术前沿!什么是python怎么学?通过这篇文字就知道了
- mysql 二级什么意思_MySQL二级等级考试归纳——PHP篇