您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

Lambda 中的异常

时间:2022-10-21 11:58:37  来源:  作者:qaseven
JAVA 流不能很好地处理已检查的异常。在本文中,深入探讨如何管理此类问题。

 

Java 引入了检查异常的概念。与早期的方法相比,强制开发人员管理异常的想法是革命性的。

如今,Java 仍然是唯一一种提供检查异常的广泛使用的语言。例如,Kotlin 中的每个异常都是未经检查的。

即使在 Java 中,新特性也与受检异常不一致:Java 内置函数式接口的签名不使用异常。当将遗留代码集成到 lambda 中时,会导致代码繁琐。这在 Streams 中很明显。

在这篇文章中,我想深入探讨如何处理此类问题。

 

代码中的问题

 

下面是一个示例代码来说明这个问题:

Stream.of("java.lang.String", "ch.frankel.blog.Dummy", "java.util.ArrayList")
.map(it -> new ForNamer().Apply(it)) // 1
.forEach(System.out::println);

 

  1. 不编译:需要捕获已检查ClassNotFoundException

 

我们必须添加一个 try/catch 块来修复编译问题。

Stream.of("java.lang.String", "ch.frankel.blog.Dummy", "java.util.ArrayList")
.map(it -> {
try {
return Class.forName(it);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
})
.forEach(System.out::println);

添加块破坏了易于阅读的管道的目的。

 

将 Try/Catch 块封装到一个类中

 

为了恢复可读性,我们需要重构代码以引入一个新类。IntelliJ IDEA 甚至提出了一条记录:

var forNamer = new ForNamer(); // 1
Stream.of("java.lang.String", "ch.frankel.blog.Dummy", "java.util.ArrayList")
.map(forNamer::apply) // 2
.forEach(System.out::println);
record ForNamer() implements Function> {
@Override
public Class apply(String string) {
try {
return Class.forName(string);
} catch (ClassNotFoundException e) {
return null;
}
}
}

 

  1. 创建单个记录对象。
  2. 重复使用它。
尝试龙目岛

 

Project Lombok 是一个编译时注释处理器,可生成额外的字节码。一个人使用正确的注释并获得结果,而无需编写样板代码。

 

Project Lombok 是一个 Java 库,可自动插入您的编辑器和构建工具,为您的 Java 增添趣味。永远不要再编写另一个 getter 或 equals 方法,使用一个注释,您的类就有一个功能齐全的构建器、自动化您的日志记录变量等等。
-龙目岛计划

 

Lombok 提供了@SneakyThrow注解:它允许人们抛出已检查的异常,而无需在自己的方法签名中声明它们。然而,它目前不适用于现有的 API。

如果您是 Lombok 用户,请注意有一个已打开的 Github 问题,其状态为停放。

 

Commons Lang 救援

 

Apache Commons Lang是一个古老的项目。它在当时很普遍,因为它提供的实用程序可能是 Java API 的一部分,但不是。这是一个比在每个项目中重新发明你的DateUtils和更好的选择。StringUtils在研究这篇文章时,我发现它仍然定期使用很棒的 API 进行维护。其中之一是FAIlableAPI。

API 由两部分组成:

 

  1. 一个包装器Stream
  2. 签名接受异常的管道方法

 

这是一个小摘录:

代码终于变成了我们一开始就期待的样子:

Stream stream = Stream.of("java.lang.String", "ch.frankel.blog.Dummy", "java.util.ArrayList");
Failable.stream(stream)
.map(Class::forName) // 1
.forEach(System.out::println);

 

修复编译时错误是不够的

 

前面的代码在运行时ClassNotFoundException抛出一个Wrapped in an 。我们满足了编译器,但我们无法指定预期的行为:UndeclaredThrowableException

 

  1. 抛出第一个异常
  2. 丢弃异常
  3. 聚合类和异常,以便我们可以在管道的最后阶段对它们采取行动
  4. 别的东西

 

为了实现这一点,我们可以利用 Vavr 的力量。Vavr 是一个将函数式编程的强大功能带入 Java 语言的库:

 

Vavr 核心是 Java 的函数库。它有助于减少代码量并增加健壮性。函数式编程的第一步是开始思考不可变的值。Vavr 提供了不可变的集合以及对这些值进行操作所需的函数和控制结构。结果很漂亮,而且很有效。
- Vavr

 

想象一下,我们想要一个收集异常和类的管道。以下是描述几个构建块的 API 摘录:

它转换为以下代码:

Stream.of("java.lang.String", "ch.frankel.blog.Dummy", "java.util.ArrayList")

.map(CheckedFunction1.liftTry(Class::forName)) // 1
.map(Try::toEither) // 2
.forEach(e -> {
if (e.isLeft()) { // 3
System.out.println("not found:" + e.getLeft().getMessage());
} else {
System.out.println("class:" + e.get().getName());

  1. 将调用包装到 VavrTry中。
  2. 将 转换Try为Either以保留异常。如果我们不感兴趣,我们可以使用 anOptional来代替。
  3. 根据是否Either包含异常left或预期结果right 采取行动。

 

到目前为止,我们还停留在 Java Streams 的世界中。它按预期工作,直到forEach看起来并不“好”。

Vavr 确实提供了自己的Stream类,它模仿 Java StreamAPI 并添加了额外的特性。让我们用它来重写管道:

var result = Stream.of("java.lang.String", "ch.frankel.blog.Dummy", "java.util.ArrayList")
.map(CheckedFunction1.liftTry(Class::forName))
.map(Try::toEither)
.partition(Either::isLeft) // 1
.map1(left -> left.map(Either::getLeft)) // 2
.map2(right -> right.map(Either::get)); // 3
result._1().forEach(it -> System.out.println("not found: " + it.getMessage())); // 4
result._2().forEach(it -> System.out.println("class: " + it.getName())); // 4

 

  1. Stream将of划分Either为两个的元组Stream。
  2. 将左侧流从 a Streamof展平Either到 a Streamof Throwable。
  3. 将右流从 a Streamof展平Either到 a Streamof Class。
  4. 做我们想做的任何事。
结论

Java 的初始设计大量使用了检查异常。编程语言的发展证明这不是一个好主意。

Java 流不能很好地处理已检查的异常。将后者集成到前者所需的代码看起来不太好。为了恢复我们期望的流的可读性,我们可以依赖 Apache Commons Lang。

汇编只代表了问题的一小部分。我们通常希望对异常采取行动,而不是停止管道或忽略异常。在这种情况下,我们可以利用 Vavr 库,它提供了一种更实用的方法。

你可以在GitHub上找到这篇文章的源代码。



Tags:Lambda   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Java Lambda 表达式各种用法,你都会了吗
Lambda表达式是 Java 8 中引入的最有影响力的功能之一。它们通过允许简洁而优雅地创建匿名函数来实现 Java 中的函数式编程。在这篇博文中,我们将探讨编写 lambda 表达式的各...【详细内容】
2023-12-25  Search: Lambda  点击:(96)  评论:(0)  加入收藏
Python进阶指南,惰性求值,lambda表达式
今天给大家介绍的是惰性求值,lambda表达式。 1.lambda表达式 在Python中,lambda表达式是一个匿名函数,它可以在需要函数对象的任何地方使用。lambda表达式的语法如下:lambda ar...【详细内容】
2023-12-13  Search: Lambda  点击:(191)  评论:(0)  加入收藏
一文详解 JDK1.8 的 Lambda、Stream、LocalDateTime
今天跟小伙伴们聊聊 Java中JDK1.8的一些新语法特性使用,主要是Lambda、Stream和LocalDate日期的一些使用讲解。LambdaLambda介绍Lambda 表达式(lambda expression)是一个匿名...【详细内容】
2023-10-10  Search: Lambda  点击:(332)  评论:(0)  加入收藏
V语言终于有lambdas了
出品 | OSC开源社区(ID:oschina2013)V 语言终于有 lambdas 了。V 是一个集合了 Go 的简单和 Rust 的安全特性的静态语言,作者表示 V 与 Go 非常相似,如果你了解 Go,那么就已经了...【详细内容】
2023-09-22  Search: Lambda  点击:(259)  评论:(0)  加入收藏
你还在用老旧的Java语法吗?Lambda表达式让你的代码更简洁!
Java Lambda表达式是自Java 8版本以来增加的一项重要特性。它可以简化代码,提高可读性和可维护性,并且使得在Java中实现函数式编程变得更加容易。本文章将深入探讨Java Lambda...【详细内容】
2023-05-08  Search: Lambda  点击:(421)  评论:(0)  加入收藏
Lambda 中的异常
Java 流不能很好地处理已检查的异常。在本文中,深入探讨如何管理此类问题。 Java 引入了检查异常的概念。与早期的方法相比,强制开发人员管理异常的想法是革命性的。如今,Java...【详细内容】
2022-10-21  Search: Lambda  点击:(329)  评论:(0)  加入收藏
Lambda架构已死,数据湖必将是风口
目前大数据架构已经走向了数据湖时代,无论是单纯的批处理模式,还是同时支持实时和离线数据处理的Lambda架构都已经过时。均不再适应现在大数据的业务发展需要。一 Lambda架构...【详细内容】
2021-07-21  Search: Lambda  点击:(382)  评论:(0)  加入收藏
玩转Java8 lambda表达式&函数式接口一
Lambda表达式简介Lambda表达式是java 1.8才开始有的重要功能,使用Lambda表达式可以替代匿名内部类,代码简洁易懂,提升工作效率。上代码:使用内部类和使用lambda实现代码量对比函...【详细内容】
2021-03-15  Search: Lambda  点击:(712)  评论:(0)  加入收藏
什么是 Lambda?该如何使用?
如果你想把“一块代码”赋给一个Java变量,应该怎么做呢?比如,我想把右边那块代码,赋给一个叫做aBlockOfCode的Java变量:...【详细内容】
2020-03-08  Search: Lambda  点击:(296)  评论:(0)  加入收藏
Java回调的四种写法:反射+直接调用+接口调用+Lambda表达式
1. 引言在计算机程序设计中,回调函数,简称回调(Callback),是指通过函数参数传递到其他代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。以上是维...【详细内容】
2020-02-17  Search: Lambda  点击:(295)  评论:(0)  加入收藏
▌简易百科推荐
Java 8 内存管理原理解析及内存故障排查实践
本文介绍Java8虚拟机的内存区域划分、内存垃圾回收工作原理解析、虚拟机内存分配配置,以及各垃圾收集器优缺点及场景应用、实践内存故障场景排查诊断,方便读者面临内存故障时...【详细内容】
2024-03-20  vivo互联网技术    Tags:Java 8   点击:(15)  评论:(0)  加入收藏
如何编写高性能的Java代码
作者 | 波哥审校 | 重楼在当今软件开发领域,编写高性能的Java代码是至关重要的。Java作为一种流行的编程语言,拥有强大的生态系统和丰富的工具链,但是要写出性能优异的Java代码...【详细内容】
2024-03-20    51CTO  Tags:Java代码   点击:(24)  评论:(0)  加入收藏
在Java应用程序中释放峰值性能:配置文件引导优化(PGO)概述
译者 | 李睿审校 | 重楼在Java开发领域,优化应用程序的性能是开发人员的持续追求。配置文件引导优化(Profile-Guided Optimization,PGO)是一种功能强大的技术,能够显著地提高Ja...【详细内容】
2024-03-18    51CTO  Tags:Java   点击:(27)  评论:(0)  加入收藏
Java生产环境下性能监控与调优详解
堆是 JVM 内存中最大的一块内存空间,该内存被所有线程共享,几乎所有对象和数组都被分配到了堆内存中。堆被划分为新生代和老年代,新生代又被进一步划分为 Eden 和 Survivor 区,...【详细内容】
2024-02-04  大雷家吃饭    Tags:Java   点击:(57)  评论:(0)  加入收藏
在项目中如何避免和解决Java内存泄漏问题
在Java中,内存泄漏通常指的是程序中存在一些不再使用的对象或数据结构仍然保持对内存的引用,从而导致这些对象无法被垃圾回收器回收,最终导致内存占用不断增加,进而影响程序的性...【详细内容】
2024-02-01  编程技术汇  今日头条  Tags:Java   点击:(70)  评论:(0)  加入收藏
Java中的缓存技术及其使用场景
Java中的缓存技术是一种优化手段,用于提高应用程序的性能和响应速度。缓存技术通过将计算结果或者经常访问的数据存储在快速访问的存储介质中,以便下次需要时可以更快地获取。...【详细内容】
2024-01-30  编程技术汇    Tags:Java   点击:(73)  评论:(0)  加入收藏
JDK17 与 JDK11 特性差异浅谈
从 JDK11 到 JDK17 ,Java 的发展经历了一系列重要的里程碑。其中最重要的是 JDK17 的发布,这是一个长期支持(LTS)版本,它将获得长期的更新和支持,有助于保持程序的稳定性和可靠性...【详细内容】
2024-01-26  政采云技术  51CTO  Tags:JDK17   点击:(90)  评论:(0)  加入收藏
Java并发编程高阶技术
随着计算机硬件的发展,多核处理器的普及和内存容量的增加,利用多线程实现异步并发成为提升程序性能的重要途径。在Java中,多线程的使用能够更好地发挥硬件资源,提高程序的响应...【详细内容】
2024-01-19  大雷家吃饭    Tags:Java   点击:(107)  评论:(0)  加入收藏
这篇文章彻底让你了解Java与RPA
前段时间更新系统的时候,发现多了一个名为Power Automate的应用,打开了解后发现是一个自动化应用,根据其描述,可以自动执行所有日常任务,说的还是比较夸张,简单用了下,对于office、...【详细内容】
2024-01-17  Java技术指北  微信公众号  Tags:Java   点击:(99)  评论:(0)  加入收藏
Java 在 2023 年仍然流行的 25 个原因
译者 | 刘汪洋审校 | 重楼学习 Java 的过程中,我意识到在 90 年代末 OOP 正值鼎盛时期,Java 作为能够真正实现这些概念的语言显得尤为突出(尽管我此前学过 C++,但相比 Java 影响...【详细内容】
2024-01-10  刘汪洋  51CTO  Tags:Java   点击:(78)  评论:(0)  加入收藏
站内最新
站内热门
站内头条