请求重构Java代码以避免共享可变状态
重构方案
方案1:使用Guava分区工具+流收集(推荐)
如果项目已引入Guava依赖,这种方式最简洁直观:
import com.google.common.collect.Lists; // 生成目标数字列表 List<Integer> numbers = Stream.iterate(1, e -> e + 1) .limit(5000) .collect(Collectors.toList()); // 按500条为一组拆分列表,替代原AtomicInteger的分组逻辑 List<List<Integer>> partitionedNumbers = Lists.partition(numbers, 500); // 无共享状态收集所有Cat数据 List<Cat> catList = partitionedNumbers.stream() .map(catRepo::fetchCats) .flatMap(List::stream) .collect(Collectors.toList()); // 同理收集所有Dog数据 List<Dog> dogList = partitionedNumbers.stream() .map(dogRepo::fetchDogs) .flatMap(List::stream) .collect(Collectors.toList());
方案2:不依赖Guava,自定义分区逻辑
若不想引入第三方依赖,可自行实现分区逻辑:
List<Integer> numbers = Stream.iterate(1, e -> e + 1) .limit(5000) .collect(Collectors.toList()); int batchSize = 500; // 手动按批次拆分列表 List<List<Integer>> partitionedNumbers = IntStream.range(0, (numbers.size() + batchSize - 1) / batchSize) .mapToObj(i -> numbers.subList(i * batchSize, Math.min((i + 1) * batchSize, numbers.size()))) .collect(Collectors.toList()); // 同样通过流收集最终结果 List<Cat> catList = partitionedNumbers.stream() .map(catRepo::fetchCats) .flatMap(List::stream) .collect(Collectors.toList()); List<Dog> dogList = partitionedNumbers.stream() .map(dogRepo::fetchDogs) .flatMap(List::stream) .collect(Collectors.toList());
关键改动说明
- 替换分区方式:原代码依赖
AtomicInteger的副作用实现分组,逻辑晦涩且易出问题。改用工具类或自定义分区,代码可读性更强,无隐含副作用。 - 消除共享可变集合:不再通过外部共享列表+
addAll的方式修改状态,而是利用流的map+flatMap+collect操作,直接从每个批次的结果合并出最终列表,彻底规避共享可变问题,线程安全(即使改为并行流也无需额外同步)。 - 函数式风格优化:使用方法引用替代冗余lambda表达式,代码更简洁紧凑。
可选优化:并行处理
如果数据库查询支持并行执行,可将stream()改为parallelStream()提升效率,由于无共享状态,线程安全完全有保障:
List<Cat> catList = partitionedNumbers.parallelStream() .map(catRepo::fetchCats) .flatMap(List::stream) .collect(Collectors.toList());
内容的提问来源于stack exchange,提问作者Pratap
相关产品推荐
相关产品推荐

