Skip to content
章节导航

Collectors.joining() 是用于将流中的字符串元素连接成一个字符串的收集器。它有多个重载版本,提供不同的连接方式。

三个主要重载版本

java
// 1. 最简单的版本 - 直接连接
public static Collector<CharSequence, ?, String> joining()

// 2. 指定分隔符
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter)

// 3. 指定分隔符、前缀和后缀
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, 
 CharSequence prefix, 
 CharSequence suffix)

基本用法

java
List<String> fruits = Arrays.asList("apple", "banana", "cherry");
 
 // 1. 直接连接(无分隔符)
 String noDelimiter = fruits.stream()
     .collect(Collectors.joining());
 System.out.println("直接连接: " + noDelimiter); // "applebananacherry"
 
 // 2. 用逗号分隔
 String withComma = fruits.stream()
     .collect(Collectors.joining(", "));
 System.out.println("逗号分隔: " + withComma); // "apple, banana, cherry"
 
 // 3. 用分隔符、前缀和后缀
 String withAll = fruits.stream()
     .collect(Collectors.joining(", ", "[", "]"));
 System.out.println("完整格式: " + withAll); // "[apple, banana, cherry]"
 
 // 4. 复杂分隔符
 String complex = fruits.stream()
     .collect(Collectors.joining(" -> "));
 System.out.println("箭头分隔: " + complex); // "apple -> banana -> cherry"

核心特性

1. 处理 null 值

java
List<String> words = Arrays.asList("Hello", null, "World", null, "!");
 
 // ❌ 包含 null 值会抛出 NullPointerException
 // String bad = words.stream().collect(Collectors.joining(" "));
 
 // ✅ 先过滤 null 值
 String good = words.stream()
     .filter(Objects::nonNull) // 过滤 null
     .collect(Collectors.joining(" "));
 System.out.println("过滤 null: " + good); // "Hello World !"
 
 // ✅ 使用 map 将 null 转换为空字符串
 String withDefault = words.stream()
     .map(word -> word != null ? word : "") // 映射,替换成空串
     .collect(Collectors.joining(" "));
 System.out.println("null 转空字符串: " + withDefault); // "Hello  World  !"
 
 // ✅ 使用 map 将 null 转换为占位符
 String withPlaceholder = words.stream()
     .map(word -> word != null ? word : "(null)") // 映射
     .collect(Collectors.joining(", "));
 System.out.println("使用占位符: " + withPlaceholder); 
 // "Hello, (null), World, (null), !"

2. 空流处理

java
// 空流直接连接
 String empty = Stream.<String>empty()
     .collect(Collectors.joining());
 System.out.println("空流: '" + empty + "'"); // ""
 
 // 空流带分隔符
 String emptyWithDelimiter = Stream.<String>empty()
     .collect(Collectors.joining(", "));
 System.out.println("空流带分隔符: '" + emptyWithDelimiter + "'"); // ""
 
 // 空流带前缀后缀
 String emptyWithWrapper = Stream.<String>empty()
     .collect(Collectors.joining(", ", "[", "]"));
 System.out.println("空流带包装: '" + emptyWithWrapper + "'"); // "[]"
 
 // 只有一个元素
 String single = Stream.of("apple")
     .collect(Collectors.joining(", ", "[", "]"));
 System.out.println("单个元素: '" + single + "'"); // "[apple]"
 
 // 两个元素
 String two = Stream.of("apple", "banana")
     .collect(Collectors.joining(", ", "[", "]"));
 System.out.println("两个元素: '" + two + "'"); // "[apple, banana]"

3. 与其他操作的链式调用

java
List<String> names = Arrays.asList("alice", "bob", "charlie", "diana");
 
 // 链式操作:过滤 -> 转换 -> 连接
 String result = names.stream()
     .filter(name -> name.length() > 3) // 长度大于3
     .map(String::toUpperCase)   // 转为大写
     .sorted()     // 排序
     .collect(Collectors.joining(" | "));      // 连接
 
 System.out.println("链式操作结果: " + result);
 // "ALICE | CHARLIE | DIANA"
 
 // 更复杂的链式操作
 String complex = names.stream()
     .map(name -> name.substring(0, 1).toUpperCase() + name.substring(1))
     .sorted(Comparator.comparingInt(String::length).reversed())
     .collect(Collectors.joining("\n  - ", "Names:\n  - ", "\nEnd of list"));
 
 System.out.println(complex);
 // Names:
 //   - Charlie
 //   - Diana
 //   - Alice
 //   - Bob
 // End of list

与其他方法的对比:

方法优点缺点适用场景
Collectors.joining()简洁,链式调用可能内存占用大Stream API 中的字符串连接
StringBuilder性能最佳代码较冗长非流场景,性能要求高
StringJoiner灵活控制格式需要额外创建对象需要自定义分隔符和前后缀
String.join()最简单功能有限集合直接连接