1. 概述

本教程将介绍 Guava 库中的 JoinerSplitter 的使用方式。我们将通过 Joiner 将集合转换为字符串,同时使用 Splitter 将字符串拆分为集合。

2. 使用 JoinerList 转换为 String

先来看一个简单的例子:使用 Joiner 把一个 List 合并为一个字符串。在下面的例子中,我们使用逗号 , 作为分隔符将名字列表拼接成一个字符串:

@Test
public void whenConvertListToString_thenConverted() {
    List<String> names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
    String result = Joiner.on(",").join(names);

    assertEquals(result, "John,Jane,Adam,Tom");
}

小技巧:这种方式比手动拼接字符串要优雅得多,而且性能更好。

3. 使用 JoinerMap 转换为 String

接着来看如何使用 JoinerMap 转换为字符串。在下面的例子中,我们使用 withKeyValueSeparator() 来指定键值之间的分隔符:

@Test
public void whenConvertMapToString_thenConverted() {
    Map<String, Integer> salary = Maps.newHashMap();
    salary.put("John", 1000);
    salary.put("Jane", 1500);
    String result = Joiner.on(" , ").withKeyValueSeparator(" = ")
                                    .join(salary);

    assertThat(result, containsString("John = 1000"));
    assertThat(result, containsString("Jane = 1500"));
}

⚠️ 注意:Map 的顺序可能因实现而异,这里只是演示格式化输出的方式。

4. 合并嵌套集合

再来看一个进阶用法:合并嵌套集合为字符串。下面的例子中,我们先将每个子列表转换为字符串,再用分号 ; 连接:

@Test
public void whenJoinNestedCollections_thenJoined() {
    List<ArrayList<String>> nested = Lists.newArrayList(
      Lists.newArrayList("apple", "banana", "orange"),
      Lists.newArrayList("cat", "dog", "bird"),
      Lists.newArrayList("John", "Jane", "Adam"));
    String result = Joiner.on(";").join(Iterables.transform(nested,
      new Function<List<String>, String>() {
          @Override
          public String apply(List<String> input) {
              return Joiner.on("-").join(input);
          }
      }));

    assertThat(result, containsString("apple-banana-orange"));
    assertThat(result, containsString("cat-dog-bird"));
    assertThat(result, containsString("John-Jane-Adam"));
}

💡 提示:Iterables.transform() 是 Guava 中用于集合转换的利器。

5. 使用 Joiner 时处理 null 值

在使用 Joiner 时,null 值的处理是个常见问题。

跳过 null 值

使用 skipNulls() 可以跳过 null 值:

@Test
public void whenConvertListToStringAndSkipNull_thenConverted() {
    List<String> names = Lists.newArrayList("John", null, "Jane", "Adam", "Tom");
    String result = Joiner.on(",").skipNulls().join(names);

    assertEquals(result, "John,Jane,Adam,Tom");
}

替换 null 值

如果不想跳过 null,而想用默认值替代,可以使用 useForNull()

@Test
public void whenUseForNull_thenUsed() {
    List<String> names = Lists.newArrayList("John", null, "Jane", "Adam", "Tom");
    String result = Joiner.on(",").useForNull("nameless").join(names);

    assertEquals(result, "John,nameless,Jane,Adam,Tom");
}

⚠️ 注意:useForNull() 不会修改原始集合,只影响最终输出结果。

6. 使用 Splitter 将字符串转换为 List

接下来是拆分操作。我们使用 Splitter 把字符串拆分为列表。下面的例子中,使用 - 作为分隔符:

@Test
public void whenCreateListFromString_thenCreated() {
    String input = "apple - banana - orange";
    List<String> result = Splitter.on("-").trimResults()
                                          .splitToList(input);

    assertThat(result, contains("apple", "banana", "orange"));
}

trimResults() 会自动去除每个子串的前后空格,避免脏数据。

7. 使用 Splitter 将字符串转换为 Map

同样地,我们可以使用 Splitter 将字符串转换为 Map。使用 withKeyValueSeparator() 指定键值分隔符:

@Test
public void whenCreateMapFromString_thenCreated() {
    String input = "John=first,Adam=second";
    Map<String, String> result = Splitter.on(",")
                                         .withKeyValueSeparator("=")
                                         .split(input);

    assertEquals("first", result.get("John"));
    assertEquals("second", result.get("Adam"));
}

⚠️ 注意:输入格式必须是 key=value,key=value 的形式。

8. 使用多个分隔符进行拆分

有时候我们需要使用多个分隔符来拆分字符串。比如下面的例子中,我们使用 .,

@Test
public void whenSplitStringOnMultipleSeparator_thenSplit() {
    String input = "apple.banana,,orange,,.";
    List<String> result = Splitter.onPattern("[.,]")
                                  .omitEmptyStrings()
                                  .splitToList(input);

    assertThat(result, contains("apple", "banana", "orange"));
}

omitEmptyStrings() 是处理空字符串的利器,避免无效元素进入结果。

9. 按固定长度拆分字符串

有时我们需要按固定长度来拆分字符串。例如每 3 个字符为一组:

@Test
public void whenSplitStringOnSpecificLength_thenSplit() {
    String input = "Hello world";
    List<String> result = Splitter.fixedLength(3).splitToList(input);

    assertThat(result, contains("Hel", "lo ", "wor", "ld"));
}

💡 适用于处理定长报文或数据块。

10. 限制拆分结果数量

如果只想保留前 N 个拆分结果,可以用 limit()

@Test
public void whenLimitSplitting_thenLimited() {
    String input = "a,b,c,d,e";
    List<String> result = Splitter.on(",")
                                  .limit(4)
                                  .splitToList(input);

    assertEquals(4, result.size());
    assertThat(result, contains("a", "b", "c", "d,e"));
}

✅ 适用于只关心前几个字段的场景,比如 CSV 处理。

11. 总结

本文通过多个示例介绍了 Guava 中 JoinerSplitter 的强大功能,展示了它们在字符串与集合之间灵活转换的能力。

所有示例代码都可以在 我的 Guava GitHub 项目 中找到。这是一个基于 Eclipse 的项目,可直接导入运行。


📌 小结

功能 工具 说明
集合转字符串 Joiner 支持 List、Map、嵌套结构
字符串转集合 Splitter 灵活配置分隔符、限制数量
处理 null skipNulls() / useForNull() 控制 null 的行为
多分隔符 onPattern() 支持正则表达式
定长拆分 fixedLength() 特殊场景利器

如果你在处理字符串拼接或拆分时还在手动写循环,那真的该试试 Guava 了!


原始标题:Guava - Join and Split Collections