流上的 reduce() 操作似乎正在修改数据源(列表)Stream API Java 8
Posted
技术标签:
【中文标题】流上的 reduce() 操作似乎正在修改数据源(列表)Stream API Java 8【英文标题】:reduce() operation on stream seems to be modifying the source of data (list) Stream API Java 8 【发布时间】:2019-07-02 11:15:45 【问题描述】:我有一个名为 Transaction 的简单 POJO,它具有三个私有属性 String type、double amount 和 String id。 在主类中,我创建了几个调用构造函数的事务实例,如下所示 -
List<Transaction> transList = Arrays.asList(new Transaction(Transaction.TRANSACTION_TYPE_GROCERY,45.50,"2a"),
new Transaction(Transaction.TRANSACTION_TYPE_GROCERY,50.0,"1a"),
new Transaction(Transaction.TRANSACTION_TYPE_GROCERY,15.00,"3a"),
new Transaction(Transaction.TRANSACTION_TYPE_GROCERY,27.43,"4a"),
new Transaction(Transaction.TRANSACTION_TYPE_CLOTHING,145.0,"5a"),
new Transaction(Transaction.TRANSACTION_TYPE_CLOTHING,105.0,"6a"));
现在我使用下面的代码在这个列表上调用了下面的操作 -
Optional<Transaction> totalA = transList.stream()
.filter(x->x.getType()==Transaction.TRANSACTION_TYPE_GROCERY)
.reduce((a,b) -> Transaction z = b;
z.setAmount(a.getAmount()+b.getAmount());
return z;);
在这里,我尝试通过将 Transaction 保持为最低单位来执行归约操作,并计算所有交易金额的总和并将其设置在新的 Transaction z 中。所有这些最终都存储为可选。 在此之后,如果我尝试对 transList 数据源执行任何其他操作,我会得到不正确的结果,因为 transList 的状态会被破坏。
List<String> transactionIds = transList.stream()
.filter(x -> x.getAmount()>50.00)
.map(Transaction::getId)
.collect(Collectors.toList());
System.out.println(transactionIds);
我已经使用 reduce() 成功地为这个列表完成了 Optional 包含 Double 项和 double 返回值的实现。 我只想知道 Optional 出了什么问题,以至于它最终修改了数据源本身,这不应该发生,因为 Stream 是正常的。
【问题讨论】:
System.out.println(transactionIds) 的结果;应该是 [5a, 6a]。但是,上面的代码在执行时会返回 [1a, 3a, 4a, 5a, 6a]。 不要评论您的问题。 编辑它。 这看起来很可疑 -Transaction z = b; z.setAmount(a.getAmount()+b.getAmount());
将 b 复制到 z 不会创建对象的副本,因此您实际上是在修改 b。
一方面,您的第一个流管道中的reduce
包含一个缺陷,而您返回一个新的Transaction
并添加了amount
,并且因为type
无论如何对他们来说都是相同的(原因:过滤器),您在操作中没有考虑id
属性。这就是导致您也不会坚持所有不同的id
s 的原因。另一方面,修改现有对象实际上会立即提出这一点。
【参考方案1】:
lambda:
(a,b) -> Transaction z = b;
z.setAmount(a.getAmount()+b.getAmount());
return z;
正在修改b
参数。请记住,分配确实不复制对象,因此Transaction z = b
只是为b
指向的对象提供别名。
您可能应该使用允许指定标识和组合器的reduce
重载,操作系统只需创建对象的副本。
【讨论】:
谢谢。你们三个都回答了我的问题。【参考方案2】:使用 Optional 一切正常。您的对象是引用数据类型。
在这里,您复制了对象 Transaction z = b;
的引用。它不会创建一个新的。现在两个变量都指向同一个Transaction
。而且无论您修改z
或b
,它最终都会修改源数据
这可能有用https://javarevisited.blogspot.com/2015/09/difference-between-primitive-and-reference-variable-java.html
【讨论】:
谢谢。到目前为止,所有三个答案都正确解释了我的查询。【参考方案3】:Transaction z = b;// doesn't create a new object.
z.setAmount(a.getAmount()+b.getAmount()); //you actually set a amout to `b` object
return z; // and here you returm `b` object
【讨论】:
谢谢。到目前为止,所有三个答案都是正确的解释。以上是关于流上的 reduce() 操作似乎正在修改数据源(列表)Stream API Java 8的主要内容,如果未能解决你的问题,请参考以下文章
Google 隐式 Oauth 流上的操作失败...出了啥问题?