Java 8 lambda表达式中为什么要求外部变量为final?(相关知识汇总)

先说原因

  • 语法糖:语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。(百度百科)
  • ==注意lambda表达式,在反编译的代码中,不是一个匿名内部类,而是一个匿名的函数,其原理是将内部使用的外部变量当做方法的形参传入,==这里注意,若是内部使用的是基本类型,在内部改变外部变量时,外部变量不会变,但若是引用数据类型,在内部改变外部变量时,外部变量会发生改变。为了防止,程序员在内部对外部变量进行操作时,误以为会改变外部变量,所以报错,必须在外部显式的声明,该外部变量是不可变的,用于提示程序员。
  • 因此,为了避免这种误导混淆,保证局部变量和Lambda的变量副本的数据一致性,Java直接在语法层面强制Lambda表达式引用的局部变量不可被重新赋值。(来自语冰Yubing作者的概述,确实更为精炼。)

证明

import java.util.function.Consumer;

public class LambdaTest {
    Object instanceObj = new Object();
    private void test() {
        // 用于直接引用
        Object localObj1 = new Object();
        // 用于传参
        Object localObj2 = new Object();
        Consumer consumer = (x) -> {
            System.out.println(x);
            System.out.println(localObj1);
            System.out.println(instanceObj);
        };
        consumer.accept(localObj2);
    }
}

-----------反编译后-----------------
javac src/LambdaTest.java
javap -p src/LambdaTest.class
输出:
Compiled from "LambdaTest.java"
public class LambdaTest {
  java.lang.Object instanceObj;
  public LambdaTest();
  private void test();
  private void lambda$test$0(java.lang.Object, java.lang.Object);
}

final 和 effectively final 的区别

final int a;
a = 1;
// a = 2;
// 由于 a 是 final 的,所以不能被重新赋值

int b;
b = 1;
// b 此后再未更改
// b 就是 effectively final

int c;
c = 1;
// c 先被赋值为 1,随后又被重新赋值为 2
c = 2;
// c 就不是 effectively final
----------------来自作者 沉默王二---------------------

如何解决

  • 将变量声明为static

  • 使用变量的原子包装类

  • 建立一个中间变量

    PurchaseEntity purchaseEntity = this.getById(mergePurchaseDetailVo.getPurchaseId());
    PurchaseEntity finalPurchaseEntity = purchaseEntity;
    List<PurchaseDetailEntity> purchaseDetailEntities = purchaseDetailIds.stream().map((item) -> {
                    PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();
                    purchaseDetailEntity.setPurchaseId(finalPurchaseEntity.getId());
                    return purchaseDetailEntity;
                }).collect(Collectors.toList());
    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值