如何使用Google Collections将Map<String, String>转换为List<String>

11
我有一个由字符串组成的映射表,我希望将它转换为字符串列表,其中以空格作为键值分隔符。使用Google Collections库是否可能实现?
以下是我想要使用Google Collections实现的代码示例:
public static List<String> addLstOfSetEnvVariables(Map<String, String> env)
{
    ArrayList<String> result = Lists.newArrayList();
    for (Entry<String, String> entry : env.entrySet())
    {
        result.add(entry.getKey() + " " + entry.getValue());
    }
    return result;
}
4个回答

16

这是您要的:

private static final Joiner JOINER = Joiner.on(' ');
public List<String> mapToList(final Map<String, String> input){
    return Lists.newArrayList(
        Iterables.transform(
            input.entrySet(), new Function<Map.Entry<String, String>, String>(){
                @Override
                public String apply(final Map.Entry<String, String> input){
                    return JOINER.join(input.getKey(), input.getValue());
                }
            }));
}

更新:优化代码。使用Joiner常量比String.concat()更快。


现在,我当然会使用Java 8流。不需要外部库。

public List<String> mapToList(final Map<String, String> input) {
    return input.entrySet()
                .stream()
                .map(e -> new StringBuilder(
                             e.getKey().length()
                                     + e.getValue().length()
                                     + 1
                     ).append(e.getKey())
                      .append(' ')
                      .append(e.getValue())
                      .toString()
                )
                .collect(Collectors.toList());
}

9

函数式编程很酷,但在Java中经常会增加你不应该添加的复杂性(因为Java并不很好地支持它)。我建议你使用一个简单的循环,这样更短、更高效、更容易维护,并且不需要学习额外的库。

public static List<String> mapToList(Map<String, String> env) {
    List<String> result = new ArrayList<String>();
    for (Entry<String, String> entry : env.entrySet())
        result.add(entry.getKey() + " " + entry.getValue());
    return result;
}

一个简单的代码复杂性测试方法是计算使用的符号数量,例如:<、(、{、=、:、.、+、@,但不包括闭合括号。
plain loop 22 symbols.
functional approach 30 symbols.

考虑到需要一个List的问题,我同意。然而,如果返回类型为iterable,Guava的Iterables.transform()会更有利,因为这只是原始集合的转换视图(即客户端代码只需迭代一次值)。 - Sean Patrick Floyd
@Sean,这很酷,但这样做有什么优势吗? - Peter Lawrey
4
如果集合足够大,它会对性能和内存使用造成明显的影响,我想。但对我来说,主要的优势是我可以在不实际复制或更改它的情况下获得集合的不同视图。 - Sean Patrick Floyd
1
更不用说,谷歌之所以如此频繁地使用Iterable,是因为迭代器的一个核心思想:您并不确定您迭代的所有内容是否在主内存中。Iterable 可能在其底层实现中流式传输数据,这些数据可能无法适应主内存。通过将Iterable包装在转换函数中并在读取时进行转换,您不再需要依赖于有关Iterable的错误假设(这只发生了 98% 的时间)。 - C0M37

5
这里是使用Java 8 streams的函数式方法:
List<String> kv = map.entrySet().stream()
    .map(e -> e.getKey() + " " + e.getValue()) //or String.format if you prefer
    .collect(Collectors.toList());

如果您不拘泥于函数式风格,这里有一个更简洁的明显的for循环变量:

List<String> kv = new ArrayList<>();
map.forEach((k, v) -> kv.add(k + " " + v));

2

更为现代的解决方案

public static void main(final String[] args)
{
    final Map<String, String> m = ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3");
    final Collection<String> c = Maps.transformEntries(m, new Maps.EntryTransformer<String, String, String>()
    {
        @Override public String transformEntry(@Nullable final String key, @Nullable final String value)
        {
            return Joiner.on(' ').join(key, value);
        }
    }).values();
    System.out.println(c);
}

输出

[k1 v1, k2 v2, k3 v3]

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