这样也行,在lambda表达式中优雅的处理checked exception
简介
最近发现很多小伙伴还不知道如何在lambda表达式中优雅的处理checked exception,所以今天就重点和大家来探讨一下这个问题。
lambda表达式本身是为了方便程序员书写方便的工具,使用lambda表达式可以让我们的代码更加简洁。
可能大多数小伙伴在使用的过程中从来没有遇到过里面包含异常的情况,所以对这种在lambda表达式中异常的处理可能没什么经验。
不过没关系,今天我们就来一起探讨一下。
lambda表达式中的checked exception
java中异常的类型,大家应该是耳熟能详了,具体而言可以有两类,一种是checked exception, 一种是unchecked exception。
所谓checked exception就是需要在代码中手动捕获的异常。unchecked exception就是不需要手动捕获的异常,比如运行时异常。
首先我们定义一个checked exception,直接继承Exception就好了:
public class MyCheckedException extends Exception{
@java.io.Serial
private static final long serialVersionUID = -1574710658998033284L;
public MyCheckedException() {
super();
}
public MyCheckedException(String s) {
super(s);
}
}
接下来我们定义一个类,这个类中有两个方法,一个抛出checked exception,一个抛出unchecked exception:
public class MyStudents {
public int changeAgeWithCheckedException() throws MyCheckedException {
throw new MyCheckedException();
}
public int changeAgeWithUnCheckedException(){
throw new RuntimeException();
}
}
好了,我们首先在lambda表达式中抛出CheckedException:
public static void streamWithCheckedException(){
Stream.of(new MyStudents()).map(s->s.changeAgeWithCheckedException()).toList();
}
这样写在现代化的IDE中是编译不过的,它会提示你需要显示catch住CheckedException,所以我们需要把上面的代码改成下面这种:
public static void streamWithCheckedException(){
Stream.of(new MyStudents()).map(s-> {
try {
return s.changeAgeWithCheckedException();
} catch (MyCheckedException e) {
e.printStackTrace();
}
}).toList();
}
这样做是不是就可以了呢?
再考虑一个情况,如果stream中不止一个map操作,而是多个map操作,每个map都抛出一个checkedException,那岂不是要这样写?
public static void streamWithCheckedException(){
Stream.of(new MyStudents()).map(s-> {
try {
return s.changeAgeWithCheckedException();
} catch (MyCheckedException e) {
e.printStackTrace();
}
}).map(s-> {
try {
return s.changeAgeWithCheckedException();
} catch (MyCheckedException e) {
e.printStackTrace();
}
}).
toList();
}
实在是太难看了,也不方便书写,那么有没有什么好的方法来处理,lambda中的checked异常呢?办法当然是有的。
lambda中的unchecked exception
上面例子中我们抛出了一个checked exception,那么就必须在lambda表达式中对异常进行捕捉。
那么我们可不可以换个思路来考虑一下?
比如,把上面的checked exception,换成unchecked exception会怎么样呢?
public static void streamWithUncheckedException(){
Stream.of(new MyStudents()).map(MyStudents::changeAgeWithUnCheckedException).toList();
}
我们可以看到程序可以正常编译通过,可以减少或者几乎不需要使用try和catch,这样看起来,代码是不是简洁很多。
那么我们是不是可以考虑把checked exception转换成为unchecked exception,然后用在lambda表达式中,这样就可以简化我们的代码,给程序员以更好的代码可读性呢?
说干就干。
基本的思路就是把传入的checked exception转换为unchecked exception,那么怎么转换比较合适呢?
这里我们可以用到JDK中的类型推断,通过使用泛型来达到这样的目的:
public static <t extends="" exception,r=""> R sneakyThrow(Exception t) throws T {
throw (T) t;
}
这个方法接收一个checked exception,在内部强制转换之后,抛出T。
看看在代码中如何使用:
public static void sneakyThrow(){
Stream.of(new MyStudents()).map(s -> SneakilyThrowException.sneakyThrow(new IOException())).toList();
}
代码可以编译通过,这说明我们已经把checked异常转换成为unchecked异常了。
运行之后你可以得到下面的输出:
Exception in thread "main" java.io.IOException
at com.flydean.Main.lambda$sneakyThrow$1(Main.java:28)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.stream.Streams$StreamBuilderImpl.forEachRemaining(Streams.java:411)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:575)
at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622)
at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627)
at com.flydean.Main.sneakyThrow(Main.java:28)
at com.flydean.Main.main(Main.java:9)
从日志中,我们可以看出最后抛出的还是java.io.IOException,但是如果我们尝试对这个异常进行捕获:
public static void sneakyThrow(){
try {
Stream.of(new MyStudents()).map(s -> SneakilyThrowException.sneakyThrow(new IOException())).toList();
}catch (IOException e){
System.out.println("get exception");
}
}
在编译器中会提示编译不通过,因为代码并不会抛出IOException。如果你把IOException修改为RuntimeException,也没法捕获到最后的异常。
只能这样修改:
public static void sneakyThrow(){
try {
Stream.of(new MyStudents()).map(s -> SneakilyThrowException.sneakyThrow(new IOException())).toList();
}catch (Exception e){
System.out.println("get exception");
}
}
才能最终捕获到stream中抛出的异常。所以如果你使用了我这里说的这种异常转换技巧,那就必须要特别注意这种异常的捕获情况。
对lambda的最终改造
上面可以封装异常了是不是就完成了我们的工作了呢?
并不是,因为我们在map中传入的是一个Function而不是一个专门的异常类。所以我们需要对Function进行额外的处理。
首先JDK中的Function中必须实现这样的方法:
R apply(T t);
如果这个方法里面抛出了checked Exception,那么必须进行捕获,如果不想捕获的话,我们可以在方法申明中抛出异常,所以我们需要重新定义一个Function,如下所示:
@FunctionalInterface
public interface FunctionWithThrow<t, r=""> {
R apply(T t) throws Exception;
}
然后再定义一个unchecked方法,用来对FunctionWithThrow进行封装,通过捕获抛出的异常,再次调用sneakyThrow进行checked异常和unchecked异常的转换:
static <t, r=""> Function<t, r=""> unchecked(FunctionWithThrow<t, r=""> f) {
return t -> {
try {
return f.apply(t);
} catch (Exception ex) {
return SneakilyThrowException.sneakyThrow(ex);
}
};
}
最后,我们就可以在代码中优雅的使用了:
public static void sneakyThrowFinal(){
try {
Stream.of(new MyStudents()).map(SneakilyThrowException.unchecked(MyStudents::changeAgeWithCheckedException)).toList();
}catch (Exception e){
System.out.println("get exception");
}
}
总结
以上就是如何在lambda表达式中优雅的进行异常转换的例子了。大家使用的过程中一定要注意最后对异常的捕获。
好了,本文的代码:
本文的例子https://github.com/ddean2009/learn-java-base-9-to-20/tree/master/lambda-and-checked-exception/
> 更多文章请看 www.flydean.com
</t,></t,></t,></t,>
这样也行,在lambda表达式中优雅的处理checked exception的更多相关文章
- 关于Linq中的Lambda表达式中OrderBy的深入理解
起因:就是一段Linq语句,OrderBy里面的i是什么? IQueryable<Student> slist = (from s in EFDB.Student select s). O ...
- Lambda 表达式中的变量范围
delegate bool D(); delegate bool D2(int i); class Test { D del; D2 del2; public void TestMethod(int ...
- java 8 lambda表达式中的异常处理
目录 简介 处理Unchecked Exception 处理checked Exception 总结 java 8 lambda表达式中的异常处理 简介 java 8中引入了lambda表达式,lam ...
- lambda表达式中无法抛出受检异常!
抛出受检异常的时候,我们的接口应该带上throw关键字,但通过lambda表达式实现的Consumer的accept方法并不带有关键字,因此在lambda表达式中不能抛出受检异常必须把它吃掉
- (转) Lambda表达式中的表达式lambda和语句lambda区别
Lambda表达式可分为表达式lambda和语句lambda 表达式lambda:表达式位于 => 运算符右侧的lambda表达式称为表达式lambda (input parameters) = ...
- Lambda表达式中的表达式lambda和语句lambda区别
Lambda表达式可分为表达式lambda和语句lambda 表达式lambda:表达式位于 => 运算符右侧的lambda表达式称为表达式lambda (input parameters) = ...
- 在Lambda表达式中使用循环变量
在C#5.0之前,如果在foreach循环中的lambda表达式里使用循环变量,那么你会发现一些意想不到的现象,例子如下: , , , }; var actions = new List<Act ...
- .Net Linq与Lambda表达式中GroupBy以多个字段分组
一.引入 基本上熟悉C#语言的没有不知道Lambda表达式的,其对于数据的处理真的是太方便了.其中分组处理的GroupBy方法在List中的使用非常广泛.正式近期一个功能需求中又遇到了,而且是需要Gr ...
- lambda表达式中的排序问题
新月新气象,10月第一篇,这也是我工作的第一天,这一篇文章我们要讲到lambda的排序问题 我是这样排序的 var list = DB.company.OrderBy(x=>x.isfreeze ...
- Lambda表达式中的GroupBy使用的正确姿势
本实例适用于:将记录中的数据进行分组得到一个一对多模型数据Model 案例中的Model 注:UserDetailes 包含User的信息和其所属部门信息 需求:将UserDetailes 的记录分组 ...
随机推荐
- JS第一节课
document.getElementById() id document.getElementsByClassName() class document.getElementsByNa ...
- login_while
# -*- coding: utf-8 -*- # @Time : 2020/7/25 22:45 # @Author : Breeze # @FileName: login_while.py use ...
- nios verify failed 问题解决。
nios 调试时碰到上图所示问题.根据下载地址可以判断下载flash.sdram都成功,这里说明电路设计和焊接都没有问题. 但是在flash地址verify failed between adress ...
- git rebase时出现的提示信息
root@host: /home/wkxnk/project$ git rebase master First, rewinding head to replay your work on top ...
- Python学习笔记--图像的进一步学习
演示地图的可视化的实现 示例: 设置全局选项 可以设置出不同的颜色,不会显得很干巴: 国内地图: 那么,我们应当如何找到相对应的颜色的编号呢? 基本步骤: 前往ab173.com网站 然后在,前端那里 ...
- DAMA数据管理知识体系指南-V1
注:只摘抄了部分个人认为需要记录的笔记,如果想完整了解请看原文 中文版序 数据管理是把业务和信息技术融合起来所必须的一整套技术.方法及相应的管理和治理过程. 它的特殊定位决定了它涉及的知识体系面广且度 ...
- 基于对象的实时空间音频渲染丨Dev for Dev 专栏
本文为「Dev for Dev 专栏」系列内容,作者为声网音频算法工程师 李嵩. 随着元宇宙概念的引入,空间音频这项技术慢慢映入大家的眼帘.关于空间音频的基础原理,我们做过一期科普视频 -- 「空间音 ...
- ElasticSearch 实现分词全文检索 - 聚合查询 cardinality
目录 ElasticSearch 实现分词全文检索 - 概述 ElasticSearch 实现分词全文检索 - ES.Kibana.IK安装 ElasticSearch 实现分词全文检索 - Rest ...
- consumer goods cloud 之后续慢慢看系列
继之前的内容和帮助文档之外,整理一些其他有用的CG资源,有时间可以深入学习一下. 零售执行: https://rise.articulate.com/share/R9_PIF3mcNMuAi4iUtA ...
- Spring Data Redis 框架
系统性学习,移步IT-BLOG 一.简介 对于类似于首页这种每天都有大量的人访问,对数据库造成很大的压力,严重时可能导致瘫痪.解决方法:一种是数据缓存.一种是网页静态化.今天就讨论数据缓存的实现 Re ...