如何用Java 8 Stream简化成本计算代码并保留原对象引用?
使用Java 8 Stream简化成本计算代码的方案
你的思路方向是对的,但原写法的问题在于把单个StartingMaterialMatrix对象作为Stream元素,没法同时处理两个blending项的逻辑。我们可以换个思路:把**每个需要计算的blending项(矩阵+浓度)**作为Stream的元素,这样就能统一复用计算逻辑,避免重复的if判断。
简化后的代码(Java 8兼容,类型安全版本)
首先,我们可以定义一个私有的内部类来封装blending项的矩阵和浓度,避免数组的强制转换:
private static class BlendingItem { private final StartingMaterial matrix; private final Double concentration; BlendingItem(StartingMaterial matrix, Double concentration) { this.matrix = matrix; this.concentration = concentration; } public StartingMaterial getMatrix() { return matrix; } public Double getConcentration() { return concentration; } } private double calculateBCMMatrixCostForAnalyte(Long startingMaterialId) { StartingMaterialMatrix smm = startingMaterialMatrixRepository.findByStartingMaterialId(startingMaterialId); return Precision.round( Stream.of( new BlendingItem(smm.getBlending1Matrix(), smm.getBlending1MatrixConcentration()), new BlendingItem(smm.getBlending2Matrix(), smm.getBlending2MatrixConcentration()) ) .filter(item -> item.getConcentration() != null) // 过滤浓度为空的项 .mapToDouble(item -> { // 复用原代码的成本计算逻辑 double materialCost = priceService.findNeatMaterialCostByStartingMaterialId(item.getMatrix().getId()); return materialCost * item.getConcentration() / 1_000_000.0; }) .sum(), // 自动累加所有有效项的成本 4 ); }
代码说明
- 封装blending项:用
BlendingItem类把每个blending的矩阵和浓度绑定在一起,保证类型安全,避免数组的强制转换。 - Stream化处理:把两个blending项转换成Stream元素,这样可以统一执行过滤、计算逻辑,替代原代码中重复的if判断和累加操作。
- 过滤无效项:通过
filter去掉浓度为null的项,对应原代码中的if (concentration != null)判断。 - 统一计算逻辑:用
mapToDouble对每个有效项计算成本,最后调用sum()自动累加,替代原代码中的手动+=操作。 - 保持精度控制:最后依然用
Precision.round保留4位小数,和原代码逻辑完全一致。
更简洁的版本(如果不介意数组的强制转换)
如果不想定义额外的类,也可以直接用Object[]来封装,虽然少了类型安全,但代码更短:
private double calculateBCMMatrixCostForAnalyte(Long startingMaterialId) { StartingMaterialMatrix smm = startingMaterialMatrixRepository.findByStartingMaterialId(startingMaterialId); return Precision.round( Stream.of( new Object[]{smm.getBlending1Matrix(), smm.getBlending1MatrixConcentration()}, new Object[]{smm.getBlending2Matrix(), smm.getBlending2MatrixConcentration()} ) .filter(item -> item[1] != null) .mapToDouble(item -> { StartingMaterial matrix = (StartingMaterial) item[0]; Double concentration = (Double) item[1]; return priceService.findNeatMaterialCostByStartingMaterialId(matrix.getId()) * concentration / 1_000_000.0; }) .sum(), 4 ); }
对你原写法的问题分析
你之前的写法把smm作为Stream的唯一元素,这样只能处理一次blending1的逻辑,没法同时处理blending2。而我们把每个blending项作为Stream元素后,就能一次性处理所有需要计算的项,既简化了重复代码,也符合Stream的设计初衷。
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

