这样也行,在lambda表达式中优雅的处理checked exception

这样,lambda,表达式,优雅,处理,checked,exception · 浏览次数 : 257

小编点评

## lambda表达式中的checked exception和unchecked exception对lambda的最终改造总结 **lambda表达式本身是为了方便程序员书写方便的工具,使用lambda表达式可以让我们的代码更加简洁。**可能大多数小伙伴在使用的过程中从未遇到过里面包含异常的情况,所以对这种在lambda表达式中异常的处理可能没什么经验。不过没关系,今天就来一起探讨一下。 **lambda表达式中的checked exception** * 可以直接继承Exception类,并在代码中进行捕获 * 可以通过catch捕获异常进行处理 **lambda表达式中的unchecked exception** * 需要在代码中对异常进行捕捉 * 可以通过try-catch捕获异常,也可以通过lambda表达式进行转换 **lambda表达式的最终改造** * 可以封装异常,通过catch捕获进行处理 * 可以通过lambda表达式进行转换,避免捕获异常 **示例** ```java public static void sneakyThrowFinal(){ try { Stream.of(new MyStudents()).map(SneakilyThrowException.unchecked(MyStudents::changeAgeWithCheckedException)).toList(); }catch (Exception e){ System.out.println("get exception"); } } ``` **其他** * lambda表达式可以并用catch捕获多个异常 * lambda表达式可以通过switch语句进行异常处理 * lambda表达式可以进行异常转换

正文

简介

最近发现很多小伙伴还不知道如何在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

与这样也行,在lambda表达式中优雅的处理checked exception相似的内容:

这样也行,在lambda表达式中优雅的处理checked exception

简介 最近发现很多小伙伴还不知道如何在lambda表达式中优雅的处理checked exception,所以今天就重点和大家来探讨一下这个问题。 lambda表达式本身是为了方便程序员书写方便的工具,使用lambda表达式可以让我们的代码更加简洁。 可能大多数小伙伴在使用的过程中从来没有遇到过里面包

【ASP.NET Core】标记帮助器——抽象层

标记帮助器,即 Tag Helpers。这个嘛,就直接翻译了,叫“标记帮助器”,虽然不好听,但只能这样了。当然你翻译为“标记增强器”也行。 所谓标记帮助器,就是针对 HTML 标签(不管是标准的还是自己命名的)进行扩展的做法。它是以 Razor 为基础的,服务于开发人员的。在服务器端用 C# 代码来

【动画进阶】类 ChatGpt 多行文本打字效果

今天我们来学习一个有意思的多行文本输入打字效果,像是这样: 这个效果其实本身并非特别困难,实现的方式也很多,在本文中,我们更多的会聚焦于整个多行打字效果最后的动态光标的实现。 也就是如何在文本不断变长,在不确定行数的情况下,让文字的最末行右侧处,一直有一个不断闪烁的光标效果: 单行文本打字效果 在此

Mysql索引覆盖

通常情况下,我们创建索引的时候只关注 where 条件,不过这只是索引优化的一个方向。优秀的索引设计应该纵观整个查询,而不仅仅是 where 条件部分,还应该关注查询所包含的列。索引确实是一种高效的查找数据方式,但是 mysql 也可以从索引中直接获取数据,这样就不在需要读数据行了。

[转帖]【JVM】线程安全与锁优化

线程安全 1.定义 当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果 2.分类 (1)不可变 不可变的对象一定是线程安全的,只要一个不可变对象被正确地构建出来(没有发生thi

聊一聊 SQLSERVER 的行不能跨页

一:背景 1. 讲故事 相信有很多朋友在学习 SQLSERVER 的时候都听说过这句话,但大多都是记忆为主,最近在研究 SQLSERVER,所以我们从 底层存储 的角度来深入理解下。 二:理解数据页 1. 数据页的组织 在前面的文章中我也说过,一个 数据页 是 8k 大小,那这 8k 是如何组织的呢

Redhat7/CentOS7 网络配置与管理(nmtui、nmcli、GNOME GUI、ifcfg文件、IP命令)

Redhat7/CentOS7 网络配置与管理(nmtui、nmcli、GNOME GUI、ifcfg文件、IP命令) 背景:作为系统管理员,需要经常处理主机网络问题,而配置与管理网络的方法和工具也有好几种,这里整理分享一下网络配置与管理的几种方式。 1、NetworkManager 概述 在 Re

[转帖]最全MySQL锁讲解:页锁、共享锁、行锁、表锁、悲观锁、乐观锁

我们在操作数据库的时候,可能会由于并发问题而引起的数据的不一致性(数据冲突),如何保证数据并发访问的一致性、有效性,是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素,从这一角度来说,锁对于数据库而言就显得尤为重要。 今天就分享下MySQL相关的最全锁,希望你学习后能更

事件循环

浏览器的进程模型 何为进程? 程序运⾏需要有它⾃⼰专属的内存空间,可以把这块内存空间简单的理解为进程 每个应⽤⾄少有⼀个进程,进程之间相互独⽴,即使要通信,也需要双⽅同意 何为线程? 有了进程后,就可以运⾏程序的代码了。 运⾏代码的「⼈」称之为「线程」。 ⼀个进程⾄少有⼀个线程,所以在进程开启后会⾃

xftp 7必须更新最新版本怎么解决

下载可以查看16进制的软件: Sublime Text 运行XFTP7 双击打开是:这样的 解决方案 用Sublime Text进行打开nslicense.dll, 打开之后查找“0f88 8300”字段, 大概在864行,将88修改成83, 修改完“0f83 8300”,保存后关闭,再打开Xftp