将Java Map转换为自定义的键值对字符串

16

我有一个TreeMap<String,String>,我需要将其转换为类似于URI的字符串,然后再转回Map。 我需要设置自定义分隔符。

有没有任何工具(Guava,Apache Commons?)可以帮我完成?我知道我可以编写简单的循环,但我正在寻找一行代码解决方法 :)

例如

key    value
key1   val1
key2   val2

key1_val1|key2_val2
4个回答

43

根据David Tulig的说法,您可以通过Guava来实现此操作。

 String string = Joiner.on("|").withKeyValueSeparator("_").join(map);

相反的也可以通过以下方式实现

 Map<String, String> map = Splitter.on("|").withKeyValueSeparator("_").split(string);

2
很好的答案。只想补充一下Joiner不会自动处理空值,使用useForNull("")可以解决这个问题:Map<String, String> map = Splitter.on("|").useForNull("").withKeyValueSeparator("_").split(string); - Christopher Yang
很好的答案,但是在运行分割器后我该如何修改结果呢?我得到了“Collections$UnmodifiableMap.put”错误。 - MNFS

2

使用Java8:

private static Map<String, String> prepareMap() {
    Map<String, String> map = new LinkedHashMap<>();
    map.put("key1", "val1");
    map.put("key2", "val2");
    return map;
}

@Test
public void toStr() {
    assertEquals("key1_val1|key2_val2", prepareMap().entrySet().stream()
            .map(e -> e.getKey() + "_" + e.getValue())
            .collect(Collectors.joining("|")));
}

@Test
public void toStrFunction() {
    assertEquals("key1_val1|key2_val2", joiner("|", "_").apply(prepareMap()));
}

private static Function<Map<String, String>, String> joiner(String entrySeparator, String valueSeparator) {
    return m -> m.entrySet().stream()
            .map(e -> e.getKey() + valueSeparator + e.getValue())
            .collect(Collectors.joining(entrySeparator));
}

@Test
public void toMap() {
    assertEquals("{key1=val1, key2=val2}", Stream.of("key1_val1|key2_val2".split("\\|"))
            .map(e -> e.split("_", 2))
            .collect(Collectors.toMap(e -> e[0], e -> e.length > 1 ? e[1] : null)).toString());
}

@Test
public void toMapFunction() {
    assertEquals("{key1=val1, key2=val2}", splitter("\\|", "_").apply("key1_val1|key2_val2").toString());
}

private static Function<String, Map<String, String>> splitter(String entrySeparator, String valueSeparator) {
    return s -> Stream.of(s.split(entrySeparator))
            .map(e -> e.split(valueSeparator, 2))
            .collect(Collectors.toMap(e -> e[0], e -> e.length > 1 ? e[1] : null));
}

你应该添加一点解释。 - Mario Santini

1

这不是guava或apache commons,它是一个循环,但除了实例化字符串构建器之外,它只有一行代码:

for (Entry<String,String> entry : myMap.entrySet()) {
    sb.append(entry.getKey() + separator + entry.getValue() + "\n");
}

4
我喜欢使用StringBuilder,但是传递的参数却使用了+连接。这真是一个讽刺...哦,还有"\n"不是常量!真是个杰作! - WarrenFaith
它仍然是一个单行循环内容。此外,他的一行代码仍然存在缺失2个变量的缺陷...不良的编码风格并不能使一行代码成为有效的解决方案 :) 每个人都可以编写一个单行类...没有魔法。 - WarrenFaith
1
@WarrenFaith: 你为什么想要"\n"成为一个常量? - maaartinus
1
@maaartinus,同样的原因,“separator”可能是一个常量:内存。每次使用“something”调用append()时,都会创建一个匿名变量,其中包含“something”的内容。在循环(n)中调用它,你的内存中就有了n个“something”。使用常量,你只需要传递内存地址而不是实际内容。 - WarrenFaith
1
@WarrenFaith:这并不是真的。"\n"是一个编译时常量并被内部化。如果你指的是本地匿名变量,那就是JIT的工作,不是我的。因为使用"\n",不会分配任何堆内存。 - maaartinus
显示剩余5条评论

-2
在Java 8及以上版本中,有另一种无需外部依赖的方法:使用StringJoiner
    List<String> cities = Arrays.asList("Milan", 
                                        "London", 
                                        "New York", 
                                        "San Francisco");

    String citiesCommaSeparated = String.join(",", cities);

    System.out.println(citiesCommaSeparated);


    //Output: Milan,London,New York,San Francisco

本内容的鸣谢和示例来自于this URL (https://reversecoding.net/java-8-convert-list-string-comma/)


1
问题是关于转换地图。 - AlikElzin-kilaka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接