简介

最近发现很多小伙伴还不知道如何在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. Navicat连接Mysql报错:Client does not support authentication protocol requested by server(转载)

    Navicat连接MySQL Server8.0版本时出现Client does not support authentication protocol requested  by server:解决 ...

  2. BubbleSort,冒泡排序,C++非递归和递归实现

    1 // g++ bubble_sort.cc -Wall -O3 && ./a.exe 2 3 4 #include <iostream> 5 #include < ...

  3. NodeJS - XSS-href

    参考:https://owasp-skf.gitbook.io/asvs-write-ups/cross-site-scripting-href-xss-href/kbid-3-xss-url 输入h ...

  4. 前端基础复习之HTML

    1.web基础知识 1 1.Web基础知识 2 1.Internet 3 1.简介 4 Internet 实际上就是由计算机所组成的网络结构 5 6 服务: 7 1.Telnet 8 远程登录 9 2 ...

  5. 快速排序(Java分治法)

    快速排序(Java分治法) 文章目录 快速排序(Java分治法) 0. 分治策略 1.思路步骤 2.代码 3.复杂度分析 3.1 最好情况 3.2 最坏情况 3.3 平均情况 3.4 性能影响因素 4 ...

  6. asp.net core项目部署IIS

    1.下载对应版本的webhost 我的是2.2 下载地址:https://download.visualstudio.microsoft.com/download/pr/ba001109-03c6-4 ...

  7. Python第六章实验报告

    一.实验内容:<零基础学Python>第六章实例和实战,以及一道作业题 二.实验环境:IDLE Shell 3.9.7 三.实验目的和要求:掌握定义和调用函数.变量的作用域.匿名函数.参数 ...

  8. Python第五章实验报告

    一.实验项目名称:<零基础学Python>第五章实战.实例以及两道作业题 二.实验目的和要求:了解和掌握操作字符串的方法和正则表达式的应用 三.实验环境:IDLE(Python 3.9 6 ...

  9. ffmpeg+nginx+hls(低延迟)

    先看一下我参考的原文实现: 实现方案 https://zhuanlan.zhihu.com/p/87225094 流媒体服务器环境搭建 https://blog.csdn.net/impingo/ar ...

  10. python random包常用函数

    random.random() random.random()方法返回一个随机数,其在0至1的范围之内,以下是其具体用法: import random print ("随机数: " ...