Java流|在.map()或.forEach()之后生成重复记录
我目前正在为一种医疗产品开发订单提交功能。很简单,我要做的就是:Java流|在.map()或.forEach()之后生成重复记录,java,spring-boot,java-stream,Java,Spring Boot,Java Stream,我目前正在为一种医疗产品开发订单提交功能。很简单,我要做的就是: 查询多个表(*问题来源,未使用唯一键连接的表,这超出了我们的控制,导致查询结果与相同记录重复) 将所有3个表的数据合并到一个有效载荷中,以提交给制造商/供应商 要采取的额外步骤是,循环从步骤2检索到的所有订单列表,并插入基于今天日期+从1开始的计数器的orderNo 问题:在运行我获得的10条记录中的stream().map()(即,由于上述查询问题,包含2组重复记录)后,我希望订单号为[yyyyymmdd001,yyyyymmd
orderNo
stream().map()
(即,由于上述查询问题,包含2组重复记录)后,我希望订单号为[yyyyymmdd001,yyyyymmdd002,yyyyymmdd003,yyyyymmdd004,yyyymmdd005,yyyymmdd006,yyyymmdd007,yyyyymmdd008,yyyyymmdd009,yyyymmdd010]
,然而我真正得到的是[yyyyyyyymmdd009,yyyyyyymmdd010,yyyyyyyyymmdd003,yyyyyyyyyyymmdd004,yyyyyyyyyyyyyyymmdd007,yyyyyyyyyyyyyymmdd010]
检查后,我发现缺少的purchaseNo
,即yyyyymmdd001、yyyymmdd002是yyyymmdd009和yyyymmdd010的副本,但我没想到会这样替换记录
流映射列表以插入purchaseNo:
AtomicInteger计数器=新的AtomicInteger(1);
return orderRepository.retrieveOrderByDate(日期)
.stream()
.map(订单->{
var currentCount=String.format(“%06d”,counter.getAndIncrement());
var purchaseNo=LocalDate.now();
订单。设置采购编号(采购编号);
退货单;
}).collect(toList());
以下是订单实体的大致外观:
公共类OrderEntity实现可序列化{
@短暂的
私有字符串purchaseNo;
@身份证
@列(名称=“产品代码”)
私有字符串代码;
@身份证
@列(name=“收件人\标识”)
私有字符串recipientId;
//许多其他收件人、产品和装运相关字段
}
即使在使用.forEach()时,我也尝试过并发现了相同的情况,在这个阶段,我假设这是stream()的一般行为……但仍然不太理解它
希望通过使用Java Stream获得理解此行为的帮助。谢谢!使用带有
有状态
访问对象的映射
函数通常不是一个好主意
我通常建议以函数的方式使用函数方法
(即:[静态列表]
->流Lambdas[*]
->新的[静态列表]
结果),这是常见的功能实践
对于上面的场景,如果我们真的想用这种方法来处理,我们应该引入一个SynchronizedList
(或)Set
)来处理它
来自Java文档:
如果流操作的行为参数是有状态的,则流管道结果可能是不确定的或不正确的其结果取决于流管道执行期间可能更改的任何状态。有状态lambda的一个示例是映射()的参数:
Set seen=Collections.synchronizedSet(新HashSet());
stream.parallel().map(e->{if(seen.add(e))返回0;否则返回e;})…如果在
同时,相同输入的结果可能因运行而异,
由于线程调度的差异,然而,使用无状态lambda
表达式结果总是一样的。还要注意
尝试从行为参数访问可变状态
您在安全性和性能方面的选择很糟糕;如果您
如果不同步对该状态的访问,则存在数据竞争和
因此,您的代码被破坏,但如果您同步访问
在这种情况下,您可能会面临竞争破坏您的并行性的风险
寻求从中受益。最好的方法是避免有状态
完全流式操作的行为参数;通常
一种重构流管道以避免状态性的方法
订单表中没有包含像
orderId
这样的列有什么具体原因吗?这也不是因为map、forEach或stream。加载实体时,1和2的对象与9和10的对象相同,因为它们的ID相同。因此在map Operation中,首先设置了购买编号1和2。然后在同一个对象。@GauthamM啊,问得好。这种情况更像是…主表,其中recipientId是主键。是唯一可能的链接。但不是另一个表中的唯一键。这很奇怪。但从技术上讲,顺序是由3个表组成的,这些表本身并不是真正的顺序…(如果这让人困惑,很抱歉),因此不包含OrderID这样的键。因此,我假设order表实际上不存在,但order实体是通过组合其他三个表中的数据创建的。为什么不在列表中迭代,为每个项目调用setter。在我看来,使用流处理此类问题会更干净。
Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })... Here, if the mapping operation is performed in