流:通过供应商和累加器收集

Raj*_*kar 2 java java-8 java-stream

我一直在尝试使用Stream 的收集方法,将列表转换为 HashMap。我使用下面的代码作为参考:

String result = list.parallelStream().collect(StringBuilder::new,
            (response, element) -> response.append(" ").append(element),
            (response1, response2) -> response1.append(",").append(response2.toString()))
            .toString();
Run Code Online (Sandbox Code Playgroud)

当我在 eclipse 中编写以下不完整的语句并在 ? 处执行ctrl+操作时space

Map<String,Choice> map1=  list1.stream().collect(()-> new HashMap<String,Choice>(), 
        (r,s) -> r.?,(r,s) -> r.putAll(s));
Run Code Online (Sandbox Code Playgroud)

考虑到使用 StringBuilder 的代码片段,我的期望是,累加器函数的第一个参数应该是 HashMap,因为我已使用 HashMap::new 作为供应商函数。根据这种理解,eclipse应该建议我使用HashMap的方法,但事实并非如此。

然而,这似乎工作正常

list1.stream().collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
Run Code Online (Sandbox Code Playgroud)

已经提到了Java 8 Int Stream Collect with StringBuilder,但是,这方面运气不佳。

Eug*_*ene 5

如果你想探索更多,supplier, accumulator, combiner你应该一开始就写得更清楚一些。

假设你有一个这样的类:

static class Foo {
    private final int id;

    private final String s;

    public Foo(int id, String s) {
        super();
        this.id = id;
        this.s = s;
    }

    public int getId() {
        return id;
    }

    public String getS() {
        return s;
    }

    @Override
    public String toString() {
        return "" + id;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您知道在这种情况下s是唯一的,您可以简单地执行以下操作:

HashMap<String, Foo> result = Arrays.asList(new Foo(1, "a"), new Foo(2, "b"))
            .stream()
            .collect(HashMap::new, 
                    (map, foo) -> map.put(foo.getS(), foo), 
                    HashMap::putAll);

    System.out.println(result); // {a=1, b=2}
Run Code Online (Sandbox Code Playgroud)

但如果s不是唯一的,您可能需要收集到 a List,这使得事情变得更加复杂:

 HashMap<String, List<Foo>> result = Arrays.asList(
            new Foo(1, "a"),
            new Foo(2, "b"),
            new Foo(3, "a"))
            .stream()
            .parallel()
            .collect(HashMap::new,
                    (map, foo) -> {
                        map.computeIfAbsent(foo.getS(), s -> new ArrayList<>()).add(foo);
                    },
                    (left, right) -> {
                        for (HashMap.Entry<String, List<Foo>> e : right.entrySet()) {
                            left.merge(
                                    e.getKey(),
                                    e.getValue(),
                                    (l1, l2) -> {
                                        l1.addAll(l2);
                                        return l1;
                                    });
                        }
                    });

    System.out.println(result); // {a=[1, 3], b=[2]}
Run Code Online (Sandbox Code Playgroud)

  • @FedericoPeraltaSchaffner 我有点错过了(`computeIfAbsent`):)特别是因为它也出现在文档中......谢谢。 (2认同)