目录
- Local variable must be final or effectively final
- 错误原因
- 解决办法
- 按照要求定义为final(不符合实情,很多时候是查库获取的变量值)
- 使用原子类存储变量,保证一致性
- AtomicReference
- 常用原子类
- 其它
Local variable must be final or effectively final
错误原因
-
在内部类或匿名内部类中引用了一个在外部类中定义的局部变量,那么这个局部变量必须是
final
或effectively final
的- Final 变量:指一旦被赋值后不能再修改的变量。
- Effectively Final 变量:没有显式声明为 final,但是在变量初始化后没有被再次赋值的变量。
-
为什么要求局部变量是
final
或effectively final
,为了保持一致性- 当内部类引用了外部类的局部变量时,实际上内部类会持有该局部变量的一个副本。由于内部类的生命周期可以超过外部方法的执行周期,如果外部方法的局部变量是可修改的,那么当该方法结束后,局部变量可能已经被修改,而内部类还要继续使用旧的值,这就会导致不一致性和错误的结果。
-
Lambda表达式经常遇到这种错是因为它本质上是一个匿名内部类的简化写法。因此需要符合
Local variable must be final or effectively final
的规则
解决办法
按照要求定义为final(不符合实情,很多时候是查库获取的变量值)
使用原子类存储变量,保证一致性
Java8API官网
AtomicReference
AtomicReference
我们在这里主要使用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) -> {}); }
-
存储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); // 比较并更新值
比如跳出结束循环
-
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<List<String>>
是否等价 AtomicReferenceArray<String>
- 不等价
AtomicReference<List<String>>
是一个持有List<String>
对象引用的AtomicReference
。它提供原子操作来更新和访问对List<String>
对象的引用。你可以通过AtomicReference
持有的引用来修改和获取列表的内容。
AtomicReference<List<String>> atomicRef = new AtomicReference<>(new ArrayList<>());
List<String> list = atomicRef.get(); // 获取当前列表的引用
list.add("Hello"); // 通过引用修改列表
atomicRef.set(new ArrayList<>()); // 更新对新列表的引用
AtomicReferenceArray<String>
是一个持有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> 操作的是单个对 List 对象的引用,而 AtomicReferenceArray 操作的是一个数组中的元素,每个元素都有独立的索引。因此,根据要操作的数据结构是单个引用对象还是数组,选择合适的原子类非常重要。