简介

最近发现很多小伙伴还不知道如何在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 -&gt; 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 -&gt; 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 -&gt; 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 -&gt; {
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的更多相关文章

  1. 关于Linq中的Lambda表达式中OrderBy的深入理解

    起因:就是一段Linq语句,OrderBy里面的i是什么? IQueryable<Student> slist = (from s in EFDB.Student select s). O ...

  2. Lambda 表达式中的变量范围

    delegate bool D(); delegate bool D2(int i); class Test { D del; D2 del2; public void TestMethod(int ...

  3. java 8 lambda表达式中的异常处理

    目录 简介 处理Unchecked Exception 处理checked Exception 总结 java 8 lambda表达式中的异常处理 简介 java 8中引入了lambda表达式,lam ...

  4. lambda表达式中无法抛出受检异常!

    抛出受检异常的时候,我们的接口应该带上throw关键字,但通过lambda表达式实现的Consumer的accept方法并不带有关键字,因此在lambda表达式中不能抛出受检异常必须把它吃掉

  5. (转) Lambda表达式中的表达式lambda和语句lambda区别

    Lambda表达式可分为表达式lambda和语句lambda 表达式lambda:表达式位于 => 运算符右侧的lambda表达式称为表达式lambda (input parameters) = ...

  6. Lambda表达式中的表达式lambda和语句lambda区别

    Lambda表达式可分为表达式lambda和语句lambda 表达式lambda:表达式位于 => 运算符右侧的lambda表达式称为表达式lambda (input parameters) = ...

  7. 在Lambda表达式中使用循环变量

    在C#5.0之前,如果在foreach循环中的lambda表达式里使用循环变量,那么你会发现一些意想不到的现象,例子如下: , , , }; var actions = new List<Act ...

  8. .Net Linq与Lambda表达式中GroupBy以多个字段分组

    一.引入 基本上熟悉C#语言的没有不知道Lambda表达式的,其对于数据的处理真的是太方便了.其中分组处理的GroupBy方法在List中的使用非常广泛.正式近期一个功能需求中又遇到了,而且是需要Gr ...

  9. lambda表达式中的排序问题

    新月新气象,10月第一篇,这也是我工作的第一天,这一篇文章我们要讲到lambda的排序问题 我是这样排序的 var list = DB.company.OrderBy(x=>x.isfreeze ...

  10. Lambda表达式中的GroupBy使用的正确姿势

    本实例适用于:将记录中的数据进行分组得到一个一对多模型数据Model 案例中的Model 注:UserDetailes 包含User的信息和其所属部门信息 需求:将UserDetailes 的记录分组 ...

随机推荐

  1. vue3 技术浏览 收藏

    Vue3教程:Vue3.0 + Vant3.0 搭建种子项目 链接:https://www.cnblogs.com/han-1034683568/p/13875663.html

  2. 表格CSS

    .tab{border:1px solid #cad9ea;color:#666;} .tab th {background-image: url(th_bg1.gif);background-rep ...

  3. npm publish命令

    npm publish . 注意后面有个点,否则会报错

  4. Laravel自定义JSON错误消息 The given data was invalid.

    Laravel自定义错误消息 在Laravel验证请求时出现错误,默认会返回如下的错误: 可以看到JSO结构中的message为The given data was invalid.而并非是我们具体自 ...

  5. tag 总结

    通用的: (((masterpiece))),((best quality)),ultra-detailed,extremely detailed CG unity 8k wallpaper,best ...

  6. winform导出excel报'object' does not contain a definition for 'get_Range'的问题

    现手上有个老项目采用.net framework3.0开发,改成4.0后,excel导出报'object' does not contain a definition for 'get_Range'的 ...

  7. ideal中热部署JRebal的设置

    1.ideal中安装插件: 2.打开网址:https://www.guidgen.com/   打开链接获取新的GUID码 3.网址和UUID码拼接:http://127.0.0.1:8888/ca3 ...

  8. SQL语句用法总结

    use quan56_goods; 使用数据库 show tables; 展示数据表 模糊查询 select * from tb_brand where name like '%林%'; 顺序 书写顺 ...

  9. c# form-data表单提交,post form上传数据、文件

    引用自:https://www.cnblogs.com/DoNetCShap/p/10696277.html 表单提交协议规定:要先将 HTTP 要求的 Content-Type 设为 multipa ...

  10. 信创国产化,试试 Solon v2.2.2

    Solon 是一个高效的 Java 应用开发框架:更快.更小.更简单.它不是 Spring.没有用 Servlet.也无关 JavaEE,是一个有自己接口标准的开放生态.可以为应用软件国产化提供支持, ...