这是一个关于示例项目的基本问题,因为我仍在学习Java8个特性的最佳实践。
假设我有一个OrderDetail对象,该对象表示OrderDetail的List。同时,OrderDetail
包含一个源代码
和一个命运
,以及数量
和产品
。
对于本例,我将把产品
从源
移动到命运
,这两个都是产品仓库
对象,具有availableStock
属性,这将受到订单
结果的影响。
现在,我需要更新所有源代码和
destiny
-ie的availableStock
。库存应在destiny
-ies增加,在source
s减少OrderDetail
的数量。由于
destiny
和source
属于同一类型,我可以同时更新它们。问题是,当然,它们是不同的属性。
我的第一个想法是:
//Map keeps record of the sum of products moved from the source. Key is the id the Product
HashMap<Integer, Double> quantities;
ArrayList<OrderDetail> orderDetails;
/**
* This could've been a single stream, but I divided it in two for readability here
* If not divided, the forEach() method from ArrayList<> might been enough though
*/
public void updateStock() {
List<ProductWarehouse> updated = new ArrayList<>();
orderDetails.stream()
.map(OrderDetail::getSource)
.forEach(src -> {
src.setAvailableStock(src.getAvailableStock - quantities.get(src.getProductId()));
updated.add(src);
});
orderDetails.stream()
.map(OrderDetail::getDestiny)
.forEach(dst -> {
dst.setAvailableStock(dst.getAvailableStock + quantities.get(dst.getProductId()));
updated.add(dst);
});
productWarehouseRepository.save(updated);
}
虽然这行得通,但有一个问题:这就像Javadoc中关于“不必要的副作用”的例子。这并不完全相同,但考虑到它们的相似之处,我认为我在冒可以避免的风险。
我想到的另一个选择是使用
peek()
,它有自己的含义,因为根据javadoc,该方法主要被认为是一个调试工具。
HashMap<Integer, Double> quantities;
ArrayList<OrderDetail> orderDetails;
/**
* Either make it less readable and do one save or do one save for source and one for destiny
* I could also keep the updated list from before and addAll() the result of each .collect()
*/
public void updateStock() {
productWarehouseRepository.save(
orderDetails.stream()
.map(/*Same as above*/)
.peek(src -> {/*Same as above*/})
.collect(toList()) //static import
);
}
我也在一些博客文章中读到,应该避免
peek
。这也是因为文档说明了它的用法(主要是)。
因此,问题是:如果我想使用
Stream
API修改Collection
的属性,那么遵循最佳实践的最佳方法是什么?对于这样的例子,使用Iterable.for每个()
还是简单的增强for循环更好?老实说,我看不出像这样使用Stream
的操作会产生什么副作用,但这可能是由于缺乏经验和对应用编程接口的理解。
这个问题中的代码只是为了举例,但是如果模型或更多信息更容易理解,我可以添加它。
在这两种情况下,forEach
都是一个终端操作,因此应该改用map
如果您想避免副作用,请在map
中调用setter方法,然后将其收集到列表中,并将其添加到外部列表中。
updated.addAll(orderDetails.stream().map()...collect(Collectors.toList())
相关解决方案-如何将Java8流的元素添加到现有列表中
您希望执行两个不同的操作。
>
更新每个productWarehouse
对象
将所有ProductWarehouse
对象收集到一个列表中,以便保存
不要把这两种操作混在一起。
public void updateStock() {
orderDetails.forEach(o -> {
ProductWarehouse src = o.getSource();
src.setAvailableStock(src.getAvailableStock()-quantities.get(src.getProductId()));
ProductWarehouse dst = o.getDestiny();
dst.setAvailableStock(dst.getAvailableStock()+quantities.get(dst.getProductId()));
});
List<ProductWarehouse> updated = orderDetails.stream()
.flatMap(o -> Stream.of(o.getSource(), o.getDestiny()))
.collect(Collectors.toList());
productWarehouseRepository.save(updated);
}
试图不惜一切代价在单个流操作中执行所有内容是没有意义的。在很少的情况下,迭代两次源是费用或不能保证产生相同的元素,您可以迭代结果列表,例如。
public void updateStock() {
List<ProductWarehouse> updated = orderDetails.stream()
.flatMap(o -> Stream.of(o.getSource(), o.getDestiny()))
.collect(Collectors.toList());
for(int ix = 0; ix < updated.size(); ) {
ProductWarehouse src = updated.get(ix++);
src.setAvailableStock(src.getAvailableStock()-quantities.get(src.getProductId()));
ProductWarehouse dst = updated.get(ix++);
dst.setAvailableStock(dst.getAvailableStock()+quantities.get(dst.getProductId()));
}
productWarehouseRepository.save(updated);
}
第二次迭代绝对便宜。
问题内容: 我有以下组件会在上触发ESlint错误 。 如何在保持简洁语法和ESlint规则的同时避免警告? 我知道我可以添加注释以禁止显示警告,但是对每个组件执行此操作似乎都是多余且乏味的。 问题答案: 这里有四个选项: 1.禁用规则。 为什么? 这是避免ESLint错误的最简单方法。 为什么不? 使用no-shadow规则有助于防止使用时出现非常常见的错误。也就是说,尝试调用未连接的原始动作(
null本身不是对象,也不是Objcet的实例 问题: null代表不确定的对象, 是一个很模糊的概念, 容易产生二义性 Map.get(key)若返回value值为null,其代表的含义可能是该键指向的value值是null,亦或者该键在map中并不存在 优点: 从内存消耗和效率方面,null更加廉价 优化: Optional com.google.common.base.Optional Op
我有一个包含许多JSON文件的文件夹,我希望使用JMeter将它们并行发送到Webservice。 我已经使用BeanShell采样器将文件收集到JMeter-variables中。然后我使用了一个ForEach控制器来执行HTTP请求(参见此线程)。 但问题是,当使用线程计数>1时,JSON文件会被多次处理。每个线程循环访问自己的JSON文件列表。 您知道多个线程如何共享ForEach控制器的输
问题内容: 任何方法都可以在左右两侧(水平?)获得箱形阴影,而没有任何骇客或图像。我在用: 但它给周围的阴影。 我周围没有边界。 问题答案: 注意: 我建议您在下面查看@Hamish的答案;它不涉及此处描述的解决方案中不完善的“掩盖”。 您可以使用多个框阴影来接近;每一面一个 编辑 在顶部和底部的顶部再添加2个阴影,以遮盖流血的阴影。
问题内容: 我有几个较旧的应用程序,它们在E_NOTICE错误级别上运行时会抛出很多“ xyz未定义”和“未定义偏移”消息,因为没有使用和明确检查变量的存在。 我正在考虑通过它们使它们与E_NOTICE兼容,因为有关丢失变量或偏移量的通知可能会节省生命,可能会获得一些较小的性能改进,并且总体而言,这是一种更清洁的方法。 但是,我不喜欢什么造成数百 和S ^确实给我的代码。它变得肿,可读性降低,而没
嗨,我有很多雄辩的查询Foreach循环在我的应用程序,我试图避免这种做法可能。 示例: 我使用foreach获得我想要的东西的领域还有很多,其中一些我可能会查询10到100次——以下是我现在根据不同的堆栈溢出答案尝试的内容: 但这并没有给出我需要的数组格式,我需要一维[id]= 谢谢 非常感谢。尝试此操作会将主键作为数组键,将状态标题作为值,而不使用列名。抱歉,我刚刚意识到这个例子在foreac