findfirst_当心findFirst()和findAny()

findfirst

过滤Java 8 Stream ,通常使用findFirst()findAny()来获取在过滤器中幸存的元素。 但这可能并不能真正实现您的意思,并且可能会出现一些细微的错误。

那么

从我们的Javadoc( 此处和此处 )可以看出,这两种方法都从流中返回任意元素-除非流具有遇到顺序 ,在这种情况下, findFirst()返回第一个元素。 简单。

一个简单的示例如下所示:

public Optional<Customer> findCustomer(String customerId) {return customers.stream().filter(customer -> customer.getId().equals(customerId)).findFirst();
}

当然,这只是旧的for-each-loop的漂亮版本:

public Optional<Customer> findCustomer(String customerId) {for (Customer customer : customers)if (customer.getId().equals(customerId))return Optional.of(customer);return Optional.empty();
}

但是,这两种变体都包含相同的潜在错误:它们是基于隐含的假设建立的,即只有一个具有任何给定ID的客户。

现在,这可能是一个非常合理的假设。 也许这是一个已知的不变式,由系统的专用部分保护,并由其他人员依赖。 在这种情况下,这完全可以。

通常,代码依赖于唯一的匹配元素,但没有做任何断言。

但是在很多情况下,我不是在野外看到的。 也许客户只是从外部来源加载的,这些来源无法保证其ID的唯一性。 也许现有的错误允许两本书具有相同的ISBN。 也许搜索词允许出乎意料的许多意外匹配(有人说过正则表达式吗?)。

通常,代码的正确性取决于以下假设:存在与条件匹配的唯一元素,但它不执行或断言该元素。

更糟糕的是,不当行为完全是由数据驱动的,可能会在测试期间将其隐藏。 除非考虑到这种情况,否则我们可能会完全忽略它,直到它在生产中出现为止。

更糟糕的是,它默默地失败了! 如果只有一个这样的元素的假设被证明是错误的,我们将不会直接注意到这一点。 取而代之的是,系统会在观察到影响并查明原因之前微妙地运行一段时间。

因此,当然, findFirst()findAny()本质上没有错。 但是,使用它们很容易导致建模域逻辑中的错误。

Steven Depolo在CC-BY 2.0下发布

Steven Depolo在CC-BY 2.0下发布

快速失败

因此,让我们解决这个问题! 假设我们非常确定最多有一个匹配元素,如果没有,我们希望代码快速失败 。 通过循环,我们必须管理一些难看的状态,它看起来如下:

public Optional<Customer> findOnlyCustomer(String customerId) {boolean foundCustomer = false;Customer resultCustomer = null;for (Customer customer : customers)if (customer.getId().equals(customerId))if (!foundCustomer) {foundCustomer = true;resultCustomer = customer;} else {throw new DuplicateCustomerException();}return foundCustomer? Optional.of(resultCustomer): Optional.empty();
}

现在,流为我们提供了更好的方法。 我们可以使用经常被忽略的reduce, 文档中对此说 :

执行减少有关此流的元件,使用缔合累积功能,并返回一个可选描述的缩小值,如果有的话。 这等效于:

流减少

boolean foundAny = false;
T result = null;
for (T element : this stream) {if (!foundAny) {foundAny = true;result = element;}elseresult = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : Optional.empty();

但不限于顺序执行。

看起来不像上面的循环吗?! 疯狂的巧合...

因此,我们需要的是一个累加器,该累加器会在调用后立即抛出所需的异常:

public Optional<Customer> findOnlyCustomerWithId_manualException(String customerId) {return customers.stream().filter(customer -> customer.getId().equals(customerId)).reduce((element, otherElement) -> {throw new DuplicateCustomerException();});
}

这看起来有些奇怪,但它确实可以满足我们的要求。 为了使它更具可读性,我们应该将其放入Stream实用工具类中并给它起一个漂亮的名字:

public static <T> BinaryOperator<T> toOnlyElement() {return toOnlyElementThrowing(IllegalArgumentException::new);
}public static <T, E extends RuntimeException> BinaryOperator<T>
toOnlyElementThrowing(Supplier<E> exception) {return (element, otherElement) -> {throw exception.get();};
}

现在我们可以这样称呼它:

// if a generic exception is fine
public Optional<Customer> findOnlyCustomer(String customerId) {return customers.stream().filter(customer -> customer.getId().equals(customerId)).reduce(toOnlyElement());
}// if we want a specific exception
public Optional<Customer> findOnlyCustomer(String customerId) {return customers.stream().filter(customer -> customer.getId().equals(customerId)).reduce(toOnlyElementThrowing(DuplicateCustomerException::new));
}

目的显示代码如何?

这将实现整个流。

应该注意的是,与findFirst()findAny() ,这当然不是短路操作 ,它将实现整个流。 也就是说,如果确实只有一个元素。 当然,一旦遇到第二个元素,处理就会停止。

反射

我们已经看到findFirst()findAny()如何不足以表示流中最多剩余一个元素的假设。 如果我们要表达该假设,并确保在违反该代码时快速失败,则需要reduce(toOnlyElement())

  • 您可以在GitHub上找到代码并随意使用-它在公共领域。

首先感谢Boris Terzic使我意识到这种意图不匹配。

翻译自: https://www.javacodegeeks.com/2016/02/beware-findfirst-findany.html

findfirst

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

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

相关文章

儿童学python下哪个软件好用_【开源软件】超好用的Python学习软件!没有之一!...

可以观看视频&#xff01;文章结尾&#xff0c;有下载、安装方法&#xff01;曾几何时&#xff01;Python开始掀起了一阵狂猛的学习浪潮&#xff1f;Python那么Python为什么那么火&#xff1f;https://wenwen.sogou.com/z/q889141941.htm咱们在网上随便搜索&#xff0c;就是一大…

土木计算机2级,请教各位,我是学土木的,考计算机二级的哪个比较好?

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼谁听说近来是开学季&#xff0c;听度娘说开学季有三倍经验&#xff0c;竟然有三倍经验&#xff1f;但是就算有三倍经验我也不会借这谁听说近来是开学季&#xff0c;听度娘说开学季有三倍经验&#xff0c;竟然有三倍经验&#xff1f…

javafx_JavaFX在这里留下来!

javafx上周在网上看到了一些有关JavaFX未来的讨论。 许多人给人以Oracle将JavaFX搁置的印象。 这主要是由Shai Almog&#xff08;代号为One&#xff09;撰写的博客文章“ Should Oracle Spring Clean JavaFX”引起的。 我早些时候写了一个博客&#xff0c;“它的灵感”来自于我…

ssms2008 代码自动提示_使用 SSMS 的提示和技巧 - SQL Server Management Studio (SSMS) | Microsoft Docs...

使用 SQL Server Management Studio (SSMS) 的提示和技巧Tips and tricks for using SQL Server Management Studio (SSMS)03/13/2018本文内容本文介绍了一些使用 SQL Server Management StudioSQL Server Management Studio (SSMS) 的提示和技巧。This article gives you some…

递增星号打印解析

#include<iostream> using namespace std;//输出一个5X5递增*号图形 //分析首先需要打印出5行&#xff0c;每行打印的*号数量与当前行数相同int main() {for (int i 1; i <5; i)//循环打印确定行数为5{for (int j 0;j<i;j)//从每行第一个位置开始打印&#xff0c;…

计算机接口控制采集时序图,自动站实时数据质量控制

自动站实时数据质量控制利用极值法、比较法、综合(本文共2页)阅读全文>>通过2次自动站实时数据质量控制失败的案例,分析总结了自动气象站实时数据质量控制的经验教训。结果表明:(1)值班员必须严格执行地面气象观测规范和各项规章制度;必须充分认识建立和运行实时自动气象…

jpa语法错误_JPA陷阱/错误

jpa语法错误根据我在帮助团队和进行培训方面的经验&#xff0c;这是我遇到的一些陷阱/错误&#xff0c;它们在使用JPA的基于Java的系统中引起了一些问题。 需要一个公共的无参数构造函数 始终使用双向关联/关系 将OneToMany用于可能庞大的集合 需要一个公共的无参数构造函数…

python源码文件以什么格式结尾结尾_查看python源码,发现里面的函数都以pass结尾,那么意义何在?...

例如&#xff1a;class str(object):"""str(object) -> strstr(bytes_or_buffer[, encoding[, errors]]) -> strCreate a new string object from the given object. If encoding orerrors is specified, then the object must expose a data bufferthat …

java流式传输对象_使用Java 8在地图上流式传输

java流式传输对象在本文中&#xff0c;我将向您展示如何在标准Java映射上有效地实现Speedment Open Source流&#xff0c;并将Stream接口扩展为MapStream&#xff01; 即使在复杂的情况下&#xff0c;此添加将使保持流的具体性和可读性变得更加容易。 希望这将允许您继续流式传…

计算机学术硕士课题,硕士学术论文选题的原则分析

硕士学术论文选题的原则分析选题作为硕士学术论文写作过程的第一步&#xff0c;也是最关键的一步&#xff0c;直接影响到论文写作整个过程中&#xff0c;包括资料收集&#xff0c;发现问题&#xff0c;解决问题等一系列工作&#xff0c;决定了整篇论文的成败。硕士学术论文是对…

选择排序与冒泡排序的区别

冒泡排序&#xff1a;冒泡排序&#xff08;BubbleSort&#xff09;的基本概念是&#xff1a;依次比较相邻的两个数&#xff0c;将小数放在前面&#xff0c;大数放在后面。即在第一趟&#xff1a;首先比较第1个和第2个数&#xff0c;将小数放前&#xff0c;大数 放后。然后比较第…

冒泡排序 自带时间复杂度测试

#include<iostream> #include<time.h> using namespace std;void Sort(int List[], int n);int main() {int a[10000];int k, j;// 设置种子srand((unsigned)time(NULL));/* 生成 10 个随机数 */for (k 0; k < 10000; k){// 生成实际的随机数j rand();a[k] j…

独占线程太多怎么办_电脑内存被占用太多怎么办?

1、禁用闲置的IDE通道右键点击“我的电脑-属性”&#xff0c;然后点击“硬件”接着点击“设备管理器”&#xff0c;在其中打开“IDE ATA/PATA控制器”然后分别进入主要和次要IDE通道&#xff0c;选择“高级设置”&#xff0c;在这里找到“当前传送模式”为“不适用”的一项&…

计算机net use命令使用,网络命令net之net use应用

echo offnet use LPT1: "123456" /user:pingpai /persistent:no以上为批处理文件 "打印.bat"脚本。先介绍net use命令&#xff0c;最后看这个脚本是什么意思。以下内容来自net help use的结果。C:\Documents and Settings\ppb>net help use此命令的语…

记录日志的测试软件_教程:测试期间的日志记录

记录日志的测试软件日志记录是一种流行的解决方案&#xff0c;用于显示软件在运行时的运行状况。 但是&#xff0c;当我们使用jUnit / TestNG对应用程序进行单元测试时&#xff0c;日志记录会怎样&#xff1f; 在自动化测试执行期间&#xff0c;我们通常不希望看到日志记录消…

选择排序 自带时间复杂度分析

从当前未排序的整数中找到最小的整数&#xff0c;将它放在已排序的整数列表的最后。 #include<iostream> #include<time.h> using namespace std;void Sort(int List[], int n);int main() {int a[10000];int k, j;// 设置种子srand((unsigned)time(NULL));/* 生成…

oracle11g支持xp吗_拔掉U盘前一定需要安全弹出吗?

相信每一个使用过U盘的人&#xff0c;都经历过不安全弹出USB设备就直接拔掉&#xff0c;然后被电脑无情提示没有正确弹出USB设备的状况。拔掉U盘前点击安全弹出&#xff0c;已经成了一种默认的操作。那么&#xff0c;问题来了&#xff0c;拔掉U盘前真的需要安全弹出吗&#xff…

yili邮箱服务器配置,手把手教 个人SMTP服务器的配置 -电脑资料

导读&#xff1a;&#xff0c;因此我们要手工添加&#xff0c;管理员身份登录Windows Server 2003 系统。依次进入“控制面板→添加或删除程序→添加/删除Windows组件”&#xff0c;在弹出的“Windows组件向导”对话框中选中“电子邮件服务”选项&#xff0c;点击“详细信息”按…

java中使用kotlin_在Kotlin中使用libGDX

java中使用kotlin最近&#xff0c;我一直在阅读有关不同语言的信息&#xff0c;以及它们可以为已经拥挤的软件开发人员带来什么&#xff0c;并且一种语言对我来说很突出&#xff1a;Kotlin。 &#xff08; https://kotlinlang.org/ &#xff09; 这是一种相对较新的语言&#…

单链表的各种操作

#include<iostream> #define _CRT_SECURE_NO_WARNINGS using namespace std; typedef int DATA;struct SNode //定义节点 {DATA data;SNode* pNext; }; class CList //创建一个链表类 {SNode* m_hHead; //链表初始化char m_name[20];public:CL…