Lambda表达式常见的Local variable must be final or effectively final原因及解决办法

目录

  • Local variable must be final or effectively final
    • 错误原因
  • 解决办法
    • 按照要求定义为final(不符合实情,很多时候是查库获取的变量值)
    • 使用原子类存储变量,保证一致性
      • AtomicReference
      • 常用原子类
  • 其它

Local variable must be final or effectively final

错误原因

  • 在内部类或匿名内部类中引用了一个在外部类中定义的局部变量,那么这个局部变量必须是 finaleffectively final

    • Final 变量:指一旦被赋值后不能再修改的变量。
    • Effectively Final 变量:没有显式声明为 final,但是在变量初始化后没有被再次赋值的变量。
  • 为什么要求局部变量是 finaleffectively final ,为了保持一致性

    • 内部类引用了外部类的局部变量时,实际上内部类会持有该局部变量的一个副本。由于内部类的生命周期可以超过外部方法的执行周期,如果外部方法的局部变量是可修改的,那么当该方法结束后,局部变量可能已经被修改,而内部类还要继续使用旧的值,这就会导致不一致性和错误的结果
  • Lambda表达式经常遇到这种错是因为它本质上是一个匿名内部类的简化写法。因此需要符合 Local variable must be final or effectively final的规则

解决办法

按照要求定义为final(不符合实情,很多时候是查库获取的变量值)

使用原子类存储变量,保证一致性

Java8API官网

AtomicReference

AtomicReference
Lambda表达式常见的Local variable must be final or effectively final原因及解决办法_第1张图片
我们在这里主要使用set方法存储,以及通过get方法调用

  • 比如存储map,调用map

    // 存储Map,并且初始化new HashMap<>(),防止空指针
    AtomicReference<Map<Long, List<TestEntity>>> atomicMap = new AtomicReference<>(new HashMap<>());
    //具体逻辑代码,获取map值
    List<TestEntity> entities = this.selectList(null);
    if (CollectionUtils.isNotEmpty(scriptRelationEntities)) {
       Map<Long, List<TestEntity>> map = entities.stream().collect(Collectors.groupingBy(TestEntity::getId));
        if (map != null) {
        	//将map存放到atomicMap 
            atomicMap .set(map);
        }
    }
    //调用map,直接get()
    if(!atomicMap.get().isEmpty(){
    	atomicMap.get().forEach((key, value) -> {});
    }
    
    

    Lambda表达式常见的Local variable must be final or effectively final原因及解决办法_第2张图片
    在这里插入图片描述

  • 存储list

    AtomicReference<List<TestEntity>> atomicList = new AtomicReference<>(new ArrayList<>());
    

常用原子类

  • AtomicBoolean:用于对boolean值进行原子操作。

    AtomicBoolean atomicBoolean = new AtomicBoolean(true);
    boolean value = atomicBoolean.get(); // 获取当前boolean值
    atomicBoolean.set(false); // 设置新的boolean值
    boolean success = atomicBoolean.compareAndSet(true, false); // 比较并更新值
    

    比如跳出结束循环
    Lambda表达式常见的Local variable must be final or effectively final原因及解决办法_第3张图片

  • AtomicInteger:用于对int值进行原子操作。

    AtomicInteger atomicInteger = new AtomicInteger(0);
    int value = atomicInteger.get(); // 获取当前int值
    atomicInteger.set(5); // 设置新的int值
    int newValue = atomicInteger.incrementAndGet(); // 原子递增并获取新值
    
  • AtomicLong:用于对long值进行原子操作。

    AtomicLong atomicLong = new AtomicLong(0L);
    long value = atomicLong.get(); // 获取当前long值
    atomicLong.set(10L); // 设置新的long值
    long newValue = atomicLong.addAndGet(5L); // 原子增加并获取新值
    
  • AtomicReference:用于对对象引用进行原子操作。

    AtomicReference<String> atomicRef = new AtomicReference<>("Hello");
    String oldValue = atomicRef.get(); // 获取当前引用值
    atomicRef.set("World"); // 设置新的引用值
    boolean success = atomicRef.compareAndSet("World", "NewValue"); // 比较并更新
    
  • AtomicReferenceArray:用于对对象引用数组进行原子操作。

    AtomicReferenceArray<String> atomicArray = new AtomicReferenceArray<>(new String[]{"Hello", "World"});
    String value = atomicArray.get(0); // 获取索引0处的引用值
    atomicArray.set(1, "NewValue"); // 设置索引1处的引用值
    boolean success = atomicArray.compareAndSet(0, "Hello", "UpdatedValue"); // 比较并更新
    
  • AtomicIntegerFieldUpdater:通过反射方式实现对指定类的int字段进行原子操作。

  • AtomicLongFieldUpdater:通过反射方式实现对指定类的long字段进行原子操作。

  • AtomicReferenceFieldUpdater:通过反射方式实现对指定类的引用字段进行原子操作。

  • AtomicStampedReference:带有版本号的原子引用,用于解决ABA问题。

  • AtomicMarkableReference:带有标记位的原子引用,用于解决标记并搭配引用的场景。

其它

AtomicReference> 是否等价 AtomicReferenceArray

  • 不等价
    • AtomicReference> 是一个持有 List 对象引用的 AtomicReference。它提供原子操作来更新和访问对 List 对象的引用。你可以通过 AtomicReference 持有的引用来修改和获取列表的内容。
AtomicReference<List<String>> atomicRef = new AtomicReference<>(new ArrayList<>());
List<String> list = atomicRef.get(); // 获取当前列表的引用
list.add("Hello"); // 通过引用修改列表
atomicRef.set(new ArrayList<>()); // 更新对新列表的引用
  • AtomicReferenceArray 是一个持有 String 对象数组AtomicReferenceArray。它提供原子操作来更新和访问数组指定索引位置的元素。你可以原子化地修改和访问数组的值。
AtomicReferenceArray<String> atomicArray = new AtomicReferenceArray<>(new String[5]);
String value = atomicArray.get(0); // 获取索引0处的值
atomicArray.set(1, "Hello"); // 设置索引1处的值
boolean success = atomicArray.compareAndSet(2, "OldValue", "NewValue"); // 比较并设置索引2处的值

AtomicReference 操作的是单个对 List 对象的引用,而 AtomicReferenceArray 操作的是一个数组中的元素,每个元素都有独立的索引。因此,根据要操作的数据结构是单个引用对象还是数组,选择合适的原子类非常重要。

你可能感兴趣的:(#,Java,Daily,Record,java,原子类,lambda,匿名内部类,Local,variable)