Java 8 Stream条件Collector:动态生成适配元素数量的结果字符串
解决Java 8 Stream动态根据元素数量生成格式化字符串的问题
这确实是个很实用的场景:咱们需要用Java 8 Stream把列表转成格式化的字符串,还要根据最终处理(比如过滤后)的元素数量动态调整前缀和表述,同时尽量避免额外的中间List操作。
需求回顾
- 当列表有多个元素时,输出格式类似:
Values: 'A', 'B' added - 当列表只有一个元素时,输出格式类似:
Value 'A' added - 支持过滤操作,最终元素数量未知,要求在单Stream流程内完成处理
原有代码的局限
你最初的Collectors.joining方案虽然简洁,但没法动态调整前缀——因为joining的前缀参数是固定值,没办法根据最终收集到的元素数量来动态切换,这就满足不了咱们的需求。
解决方案:使用Collectors.collectingAndThen
咱们可以利用collectingAndThen这个收集器,它的作用是先把Stream元素收集到一个容器里,然后对这个容器执行后续的转换操作。这样就能在后续操作里拿到元素的数量,动态生成对应的格式化字符串了。
最终实现的代码(支持对比两个列表差异并生成可读字符串)如下:
import java.util.stream.Collectors; import java.util.ArrayList; import java.util.List; public class HelloWorld { public static void main(String[] args) { List<String> oldValues = new ArrayList<>(); oldValues.add("A"); oldValues.add("B"); oldValues.add("C"); List<String> newValues = new ArrayList<>(); newValues.add("A"); newValues.add("C"); newValues.add("D"); newValues.add("E"); System.out.println(HelloWorld.<String>log(oldValues, newValues, " deleted")); System.out.println(HelloWorld.<String>log(newValues, oldValues, " added")); } public static <T> String log(List<T> first, List<T> second, String postfix) { return first .stream() .filter(x -> !second.contains(x)) // 过滤出两个列表的差异元素 .map(x -> "'" + x.toString() + "'") // 给元素加上单引号 .collect(Collectors.collectingAndThen(Collectors.toList(), list -> { if (list.size() == 1) { return "Value " + list.get(0) + postfix; } if (list.size() > 1) { return "Values: " + String.join(",", list) + postfix; } return ""; // 没有元素时返回空字符串 })); } }
代码关键部分解释
- 过滤差异元素:通过
filter(x -> !second.contains(x))找出第一个列表有但第二个列表没有的元素,实现对比功能 - 格式化元素:
map操作把每个元素转换成带单引号的字符串格式 - 动态生成结果:
collectingAndThen先把元素收集到List,然后根据List的size判断:- 单个元素时用
Value前缀 - 多个元素时用
Values:前缀,并用String.join拼接元素 - 无元素时返回空字符串
- 单个元素时用
输出结果
运行代码后会得到:
Value 'B' deleted Values: 'D','E' added
内容的提问来源于stack exchange,提问作者Benedikt Gansinger
相关产品推荐
相关产品推荐

