async 打包异常_重新打包流中的异常

async 打包异常

Java 8已有两年历史,但是仍然存在社区尚未为其开发好的解决方案库的用例,甚至边缘用例。 如何处理流管道中的检查异常就是这样一个问题。 Stream操作接受的功能接口不允许实现抛出已检查的异常,但是我们可能要调用许多方法。 显然,这里存在一种紧张关系,许多开发人员都曾遇到过这种紧张关系。

我想在简短的系列文章中探讨这个主题:

重新打包流中的异常
重新打包异常以便抛出它们,而编译器不会抱怨它。
处理流中的异常
可以通过延迟错误处理来现场捕获并处理异常。
流中抛出异常
毕竟如何通过引发异常来处理延迟的错误。

我的主要目标是提出各种解决方案,并且在理想情况下,建立使讨论变得更容易的通用术语。 我还将对我的建议进行评论,并添加自己的评估意见-尽管这是次要的,但我希望它不会偏离主要目标:将想法付诸实践。

第一篇文章将研究重新打包异常,以便编译器停止抱怨。

设置场景

基本场景是流的每个频繁用户都遇到的一种或多种形式:您想在流的中间操作之一中使用的方法抛出一个已检查的异常。

在本文中,我将假定您正在尝试将字符串流解析为用户流:

Stream<User> parse(Stream<String> strings) {return strings.map(User::parse);
}

(如果您不打算将流作为参数或返回值,则假定整个流管道都在方法的范围内。以下方法适用于这两种方式,但是如果您在处理流上使用整个流,则某些评估会有所不同。点。)

不幸的是, User::parse可以抛出ParseException

public class User {public static User parse(String userString) throws ParseException {// ...}}

这导致编译器抱怨方法参考User::parse “未处理的异常:java.text.ParseException” 。 现在要做什么?

在我们研究此问题的解决方案之前,我想指出一点:我不认为Stream API与检查异常的不兼容性是可以通过其他设计克服的。 在某个时候,我可能会写一个更长的帖子来解释这一点,但是简短的版本是这样的:如果功能接口方法可以抛出检查的异常,那么将没有一种愉快的方式将其与流的惰性结合起来,因为它将是终端操作最终抛出该异常。

但是我们可以充分利用可以引发异常的函数,因此让我们在介绍该接口时对其进行介绍:

@FunctionalInterface
interface CheckedFunction<T, R, EX extends Exception> {R apply(T element) throws EX;}

这使我们可以将User::parse分配给CheckedFunction<StringUser, ParseException> 。 请注意,异常的类型是通用的,稍后将派上用场。

重新打包流中的异常

那么,您真的必须处理例外情况吗? 不知道,您能不能解决问题? 令人惊讶的答案是“是的,您可以。” 是否应该拭目以待……

包装未检查的异常

给定一个引发检查异常的函数,将其转换为引发未检查异常的函数非常容易:

Stream<User> parse(Stream<String> strings) {return strings.map(uncheckException(User::parse))
}<T, R> Function<T, R> uncheckException(CheckedFunction<T, R, Exception> function) {return element -> {try {return function.apply(element);} catch (Exception ex) {// thanks to Christian Schneider for pointing out// that unchecked exceptions need not be wrapped againif (ex instanceof RuntimeException)throw (RuntimeException) ex;elsethrow new RuntimeException(ex);}};
}

这实际上还不错。 而且,无论如何,如果您更喜欢未检查的异常,那么这将更加诱人。 另一方面,如果您重视检查的异常(对于您期望的事情可能会出错,例如错误的输入)与未检查的异常(对于实现错误)之间的区别,那么这将使您不寒而栗。

在任何情况下,流的最终使用者都必须意识到可能会引发异常,这时需要与测试或文档进行通信,这两者都比编译器更容易忽略。 感觉就像在小河里藏了一颗炸弹。

最后,请注意,这会在第一个错误发生时立即中止流-可能会或可能不会发生的事情。 如果该方法返回一个流而不是使用它,则很难确定是否可行,因为不同的调用者可能有不同的要求。

偷偷摸摸的异常

解决整个问题的另一种方法是“偷偷地”抛出异常。 该技术使用泛型来混淆编译器,并使用@SuppressWarnings使其剩余的投诉静音。

Stream<User> parse(Stream<String> strings) {return strings.map(hideException(User::parse));
}<T, R> Function<T, R> hideException(CheckedFunction<T, R, Exception> function) {return element -> {try {return function.apply(element);} catch (Exception ex) {return sneakyThrow(ex);}};
}@SuppressWarnings("unchecked")
<E extends Throwable, T> T sneakyThrow(Throwable t) throws E {throw (E) t;
}

嗯,什么? 如所承诺的, sneakyThrow方法使用泛型来欺骗编译器以抛出未经检查的异常而不声明它。 然后hideException使用它来捕获CheckedFunction可能抛出的任何异常并CheckedFunction将其重新抛出。 (如果您使用的是Lombok,请查看其@SneakyThrows批注 。)

我认为这是非常冒险的举动。 一方面,它仍然在小河中隐藏着一颗炸弹。 但是,它进一步发展了,并使炸弹难以妥善化解。 您是否曾经尝试捕获未使用throws子句声明的检查异常?

try {userStrings.stream().map(hideException(User::parse));.forEach(System.out::println);
// compile error because ParseException
// is not declared as being thrown
} catch (ParseException ex) {// handle exception
}

无法工作,因为编译器在没有方法实际抛出ParseException的假设下运行。 相反,您必须捕获Exception ,过滤掉ParseException并重新抛出其他所有内容。

哇,真烂!

不幸的是,这种技术在StackOverflow答案中得到了体现,在寻找Java流异常处理时,它在Google上的排名非常高。 公平地说,答案包含免责声明,但恐怕它可能会经常被忽略:

不用说,应该小心处理,项目中的每个人都必须意识到,未经声明的异常可能会出现在经过检查的异常中。

但是,正如我们已经看到的那样,没有很好的方法来声明/捕获这样的异常,因此我要说的是:

这是一个不错的实验,但从未真正做到! 如果确实要抛出,请包装运行时异常。

电梯例外

偷偷摸摸的问题是,这使流的消费者感到惊讶, 并且即使他们克服了这种惊讶,也很难处理该异常。 对于后者,至少有一个出路。 考虑以下功能:

<T, R, EX extends Exception> Function<T, R> liftException(CheckedFunction<T, R, EX> function) throws EX {return hideException(function);
}

它与hideException完全相同, 但是声明它抛出EX。 为什么会有帮助? 因为可以通过这种方式使编译器理解可能会抛出检查异常:

Stream<User> parse(Stream<String> strings) {return strings// does not compile because `liftException`// throws ParseException but it is unhandled.map(liftException(User::parse));
}

问题是, liftException的主体非常清楚地表明,它当然不会引发异常。 因此,在这样的示例中,我们仅看到管道的一部分,可以说使情况更加混乱。 现在,解析调用者可能会将其放入try-catch块中,期望能够很好地处理异常(如果不要对它太认真地考虑),然后当终端操作抛出该异常时仍会感到惊讶(记住它被sneakyThrow )隐藏了。

但是,如果您是从不返回流的人, liftException非常有用。 有了它,您的流管道中的一些调用就声明抛出一个已检查的异常,因此您可以将其全部放入try-catch块中:

try {userStrings.stream().map(liftException(User::parse));.forEach(System.out::println);
} catch (ParseException ex) {// handle exception
}

另外,包含管道的方法可以声明抛出异常:

List<User> parse(List<String> userStrings) throws ParseException {return userStrings.stream().map(liftException(User::parse));.collect(toList());
}

但是正如我之前所说,我认为只有在您永不返回流的情况下,此方法才有效。 因为如果这样做(即使只是偶尔这样做),则存在风险,即您或您的同事在重构期间可能会将管道拆开,从而使炸弹处于未声明的检查异常的状态,并隐藏在流中。

Sebastian Millies指出了另一个缺点,即到目前为止使用的接口和方法仅允许一个例外。 一旦一种方法声明了多个检查异常,事情就会成问题。 要么让Java派生一个公共的超类型(可能是Exception ), liftException为一个以上的异常声明其他CheckedFunction接口和liftException方法。 两者都不是很好的选择。

给定抛出异常的方法,如果需要立即抛出异常,我向您展示了两种不同的方式在流中使用它们:

  • 将检查的异常包装在运行时异常中
  • 偷偷地抛出已检查的异常,以便编译器无法识别被抛出的异常
  • 仍然偷偷摸摸地抛出,但是让utitility函数声明异常,以便编译器至少知道它被抛出了

请注意,所有这些方法都意味着流管线将在那里停止处理,除非产生副作用,否则不会产生任何结果。 我发现经常是不是我想做的事,但(因为我喜欢返回物流)。 下一篇文章通过研究如何在不中断管道的情况下当场处理异常来解决此问题。

翻译自: https://www.javacodegeeks.com/2017/02/repackaging-exceptions-streams.html

async 打包异常

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/335116.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

补码基础

关于补码&#xff0c;有如下比较有趣的演化过程: 假如计算机中使用 4 位的二进制表示数据&#xff0c;如图-2&#xff0c;最多能表示 0 到 15(10 进制)&#xff0c;之后有牛人做了 一个细微改动&#xff0c;如图-3&#xff0c;将所有二进制以 1 开头的数(大于 7 的数)放到 0 之…

身份验证错误错误指定的句柄无效_基于 Web 端的人脸识别身份验证「实践」

作者&#xff1a;沫沫 政采云前端团队转发链接&#xff1a;https://mp.weixin.qq.com/s/fRDpXixnLIy9c0Uh2tMezQ前言近些年来&#xff0c;随着生物识别技术的逐渐成熟&#xff0c;基于深度学习的人脸识别技术取得了突破性进展&#xff0c;准确率显著提高。现阶段&#xff0c;人…

打开 谷歌浏览器exe_专治各种网银不服:两步开启微软Edge浏览器IE兼容模式

此前微软已经预告过Microsoft Edge将支持IE模式&#xff0c;即可以在该浏览器下使用IE模式加载某些特定的需要的网站。不过在后续更新中微软又突然改口不再面向普通用户提供此功能&#xff0c;而企业级用户若要使用还需要管理员提前配置。现在这款浏览器的正式版已经发布&#…

aspose word 获取标题_Word干货|多级标题的自动编号怎么添加?

在对Word文档进行排版时&#xff0c;大家普遍认为的一个难点就是对多级标题添加自动编号&#xff0c;本期Word妹与大家分享相关技巧的使用。1、添加样式选中文本&#xff0c;点击开始——样式——选择标题1&#xff0c;相同的样式则可以借用F4来实现。PS&#xff1a;以同样方式…

Java集合类梳理

文章目录集合框架CollectionListList常用方法ArrayListArrayList常用方法LinkedListLinkedList常用方法VectorVector 常用方法StackStack 常用方法SetHashSetHashSet 常用方法LinkedHashSetLinkedHashSet 常用方法TreeSetTreeSet常用方法EnumSetEnumSet 常用方法MapHashMapHash…

增加第三方插件_AE插件排行!!

大家好是万能的懒懒酱After effects为视觉效果艺术家和动画设计师带来了大量的效果。然而&#xff0c;第三方开发人员提供了更多独特插件&#xff0c;供After Effects使用。在这里可以帮助你了解哪些插件是最流行的最受欢迎的。第10名&#xff1a;Looks&#xff08;多功能调色插…

mysql 连续签到天数_签到功能实现,没有你想的那么复杂(一)

1 签到定义以及作用签到&#xff0c;指在规定的簿册上签名或写一“到”字&#xff0c;表示本人已经到达。在APP中使用此功能,可以增加用户粘性和活跃度.2 技术选型redis为主写入查询,mysql辅助查询. 传统签到多数都是直接采用mysql为存储DB,在大数据的情况下数据库的压力较大.查…

java包装项目_项目包装组织

java包装项目程序包是Java的基本概念&#xff0c;是您开始用该语言编程时偶然发现的第一件事。 作为一个初学者&#xff0c;您可能不太关注软件包的结构&#xff0c;但是随着您成为经验丰富且成熟的软件开发人员&#xff0c;您开始考虑可以采取哪些措施来提高其效率。 有几个主…

如何开发 Servlet 程序

文章目录如何开发 Servlet步骤 1&#xff1a;写一个类步骤 2&#xff1a;编译步骤 3&#xff1a;打包步骤 4&#xff1a;部署步骤 5&#xff1a;启动服务器步骤 6&#xff1a;访问 servletServlet 开发示例不使用 IDE 开发&#xff08;手动编译和部署&#xff09;步骤 1&#x…

报任安书文言现象_语文老师精心总结【文言文常考点】够你从初一用到初四!...

点击本号菜单栏 免费获取学习资料▼今天给大家整理了初中文言文的一些常用知识点&#xff1a;特殊句式和古今异义&#xff0c;这些只是文言文学习模块中的一部分&#xff0c;除此之外&#xff0c;其他大家需要在平时积累的文言文知识点有下面这些&#xff1a;文言文高频词、古代…

参数化测试 junit_JUnit 5 –参数化测试

参数化测试 junitJUnit 5令人印象深刻&#xff0c;尤其是当您深入研究扩展模型和体系结构时 。 但是从表面上讲&#xff0c;编写测试的地方&#xff0c;开发的过程比革命的过程更具进化性 – JUnit 4上没有杀手级功能吗&#xff1f; 幸运的是&#xff0c;至少有一个&#xff1a…

devexpress textedit调整文字何文本框的间距_手把手教学:用PPT做效果超赞的文字效果...

本文总计&#xff1a;2391 字预计阅读时间&#xff1a;6 分钟昨天文章的头图&#xff0c;貌似反馈还不错&#xff0c;挺多人比较感兴趣。所以&#xff0c;今天就分享一下&#xff0c;这种文字排版效果&#xff0c;是怎么做出来的。而且今天的实现手法与效果&#xff0c;做了一些…

IntelliJ IDEA for Mac 如何取消双击shift键打开全局搜索弹窗

取消双击shift键打开全局搜索弹窗 按ShiftcmdA&#xff0c;打开如下图的搜索框&#xff1a; 输入Registry搜索后打开如下的窗口&#xff1a; 3. 找到“ide.suppress.double.click.handler”&#xff0c;将后面的复选框勾上&#xff0c;勾选上复选框后直接关闭退出&#xff0c;…

vb6 判断打印机是否有效_吊打面试官 | 算法之如何判断括号是否有效?

今天要讲的这道题是 bilibili 今年的笔试真题&#xff0c;也是一道关于栈的经典面试题。经过前面文章的学习&#xff0c;我想很多朋友已经看出来了&#xff0c;我接下来要写的是一个关于「算法图解」的系列文章&#xff0c;中间可能会穿插少量的其他类型的文章&#xff0c;但「…

如何理解字符编码

一直有个困惑&#xff0c;为什么计算机系统搞那么多字符编码&#xff0c;就一个Unicode统一天下不就得了&#xff0c;后来看了篇文章&#xff0c;才多少理解一丁点。 英语的国家&#xff0c;只要一个字节就可以表示全部的字符&#xff0c;一个无符合的字节可以表示256个字符&a…

框架下载_25. Scrapy 框架-下载中间件Middleware

1. Spider 下载中间件(Middleware)Spider 中间件(Middleware) 下载器中间件是介入到 Scrapy 的 spider 处理机制的钩子框架&#xff0c;您可以添加代码来处理发送给 Spiders 的 response 及 spider 产生的 item 和 request2. 激活一个下载DOWNLOADER_MIDDLEWARES要激活一个下载…

android activity 显示无焦点_Android面试题集锦之fragemnt

大家可以关注一下小编&#xff0c;小编以后会一直更新Android相关技术资料文章。创建方式静态创建首先我们需要创建一个xml文件&#xff0c;然后创建与之对应的java文件&#xff0c;通过onCreatView()的返回方法进行关联&#xff0c;最后我们需要在Activity中进行配置相关参数即…

node 安装_VUE项目迁移之node.js的安装

【摘要】由于公司的项目需要迁移到VUE中去, 所以就用到了node.js, 这里简单整理了一下node.js的安装教程和环境变量的配置【作者】田鋆鹏Node.js 安装教程1. 在node.js的官网下载安装包下载地址1: https://nodejs.org/en/下载地址2: http://nodejs.cn/直接下载.msi的安装包即可…

jsp mysql servlet_JSP+Servlet+JDBC+mysql实现的学生成绩管理系统

本系统基于JSPServletMysql一个基于JSPServletJdbc的学生成绩管理系统。涉及技术少&#xff0c;易于理解&#xff0c;适合JavaWeb初学者学习使用。难度等级&#xff1a;入门技术栈编辑器Eclipse Version: 2019-12 (4.14.0)前端技术基础&#xff1a;htmlcssJavaScript框架&#…

mariadb mysql 配置文件_MariaDB/MySQL配置文件my.cnf解读

MariaDB/MySQL的默认设置性能非常差&#xff0c;仅仅起一个功能测试的作用&#xff0c;不能用在生产环境中&#xff0c;因此要对一些参数进行调整优化。当然&#xff0c;对配置文件各参数的调整需要根据实际环境&#xff0c;不同时期不同数量级的数据进行性能优化。MySQL/Maria…