a、b、c三个方法中 c通过不了编译,并提示【lambda 表达式中使用的变量应为 final 或有效 final】
public void a(LocalTourOrder order, List<LocalOrderMoney> moneyList) {
//团款
BigDecimal receiveAmount = BigDecimal.ZERO;
//代收
BigDecimal insteadReceiveFee = BigDecimal.ZERO;
//代付
BigDecimal insteadPaymentFee = BigDecimal.ZERO;
//未收团款
BigDecimal unCollectionReceiveAmount = BigDecimal.ZERO;
if (CollUtil.isNotEmpty(moneyList)) {
for (LocalOrderMoney money : moneyList) {
Integer moneyType = money.getMoneyType();
if (OrderMoneyType.RECEIVE.getCode().equals(moneyType)) {
receiveAmount = receiveAmount.add(money.getAmount());
} else if (OrderMoneyType.INSTEAD_RECEIVE.getCode().equals(moneyType)) {
insteadReceiveFee = insteadReceiveFee.add(money.getAmount());
} else if (OrderMoneyType.INSTEAD_PAYMENT.getCode().equals(moneyType)) {
insteadPaymentFee = insteadPaymentFee.add(money.getAmount());
}
}
unCollectionReceiveAmount = receiveAmount.subtract(insteadReceiveFee).add(insteadPaymentFee);
}
order.setReceiveAmount(receiveAmount);
order.setInsteadReceiveFee(insteadReceiveFee);
order.setInsteadPaymentFee(insteadPaymentFee);
order.setUnCollectionReceiveAmount(unCollectionReceiveAmount);
}
public void b(LocalTourOrder order, List<LocalOrderMoney> moneyList) {
order.setReceiveAmount(BigDecimal.ZERO);
order.setInsteadReceiveFee(BigDecimal.ZERO);
order.setInsteadPaymentFee(BigDecimal.ZERO);
moneyList.forEach(money -> {
if (OrderMoneyType.RECEIVE.getCode().equals(money.getMoneyType())) {
order.setReceiveAmount(order.getReceiveAmount().add(money.getAmount()));
} else if (OrderMoneyType.INSTEAD_PAYMENT.getCode().equals(money.getMoneyType())) {
money.setUnCollectionAmount(money.getAmount());
order.setInsteadPaymentFee(order.getInsteadPaymentFee().add(money.getAmount()));
} else if (OrderMoneyType.INSTEAD_RECEIVE.getCode().equals(money.getMoneyType())) {
money.setUnCollectionAmount(money.getAmount());
order.setInsteadReceiveFee(order.getInsteadReceiveFee().add(money.getAmount()));
}
});
// 初始化未收款金额
order.setUnCollectionReceiveAmount(
order.getReceiveAmount().add(order.getInsteadPaymentFee())
.subtract(order.getInsteadReceiveFee()));
}
public void c(LocalTourOrder order, List<LocalOrderMoney> moneyList) {
BigDecimal receiveAmount = BigDecimal.ZERO;
BigDecimal insteadReceiveFee = BigDecimal.ZERO;
BigDecimal insteadPaymentFee = BigDecimal.ZERO;
BigDecimal unCollectionReceiveAmount = BigDecimal.ZERO;
moneyList.forEach(money -> {
Integer moneyType = money.getMoneyType();
if (OrderMoneyType.RECEIVE.getCode().equals(moneyType)) {
receiveAmount = receiveAmount.add(money.getAmount());
} else if (OrderMoneyType.INSTEAD_RECEIVE.getCode().equals(moneyType)) {
insteadReceiveFee = insteadReceiveFee.add(money.getAmount());
} else if (OrderMoneyType.INSTEAD_PAYMENT.getCode().equals(moneyType)) {
insteadPaymentFee = insteadPaymentFee.add(money.getAmount());
}
});
unCollectionReceiveAmount = receiveAmount.subtract(insteadReceiveFee).add(insteadPaymentFee);
order.setReceiveAmount(receiveAmount);
order.setInsteadReceiveFee(insteadReceiveFee);
order.setInsteadPaymentFee(insteadPaymentFee);
order.setUnCollectionReceiveAmount(unCollectionReceiveAmount);
}
1. 并发安全性
Lambda 表达式可能被传递到不同的线程中执行。如果允许 Lambda 修改外部局部变量,而局部变量是存储在栈上的(每个线程有自己的栈),当另一个线程访问该变量时,原始栈帧可能已经销毁,导致变量副本不一致,引发难以追踪的并发问题。强制 final 或有效 final 意味着变量值在捕获时就已经确定,避免了这种“可变共享状态”的风险。
2. 保持与内部类的一致性
在 Lambda 出现之前,匿名内部类就已经要求访问的局部变量必须是 final 的。Lambda 沿用了这一约束,目的是减少开发者从匿名类迁移到 Lambda 时的意外行为,也保持了语言规则的统一性。
3. 简化闭包实现
Lambda 本质上是一个闭包,它会捕获所使用的外部局部变量的值(而不是变量本身)。如果允许修改变量,就需要把变量从栈内存转移到堆内存,并通过某种引用传递机制来同步修改,这会大大增加实现复杂度和性能开销。强制 final/ effectively final 后,只需复制一份常量值到 Lambda 中,简单可靠。
4. 避免语义混淆
允许 Lambda 修改外部局部变量容易与实例字段(可随意修改)或数组元素(可修改)混淆。Java 的设计者希望开发者明确区分:局部变量是按值捕获的,不应被修改;而对象内部的状态(通过字段访问)是可以改变的。这种区分让代码意图更清晰。

275

被折叠的 条评论
为什么被折叠?



