流:收集供应商和累加器

时间:2017-07-14 20:14:59

标签: java java-8 java-stream

我一直在尝试使用collect method of Stream,将列表转换为HashMap。 我使用下面的代码作为参考:

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

当我在eclipse中写下面不完整的语句并在 ctrl + 空间处?

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

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

然而,这似乎工作正常

list1.stream().collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

已经提到Java 8 Int Stream collect with StringBuilder但是,运气不好。

4 个答案:

答案 0 :(得分:2)

将列表转换为地图? Collectors.toMap(..)可能就是您所需要的。

javadocs有几个很好的例子:https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toMap-java.util.function.Function-java.util.function.Function-

答案 1 :(得分:2)

如果你想探索更多的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;
    }
}

如果您知道,在这种情况下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}

但如果s不唯一,您可能需要收集到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]}

答案 2 :(得分:1)

根据你的评论,我想你可以这么简单。

List<Choice> choices = new ArrayList<>();

Map<String, Integer> map = choices.stream().collect(Collectors.toMap(Choice::getString, Choice::getID);

我建议使用Collectors及其静态方法,而不是编写自己的供应商和累加器,这些方法用于将流传输到任何类型的集合。

修改 如果地图的值必须为Choice。函数接口具有名为identity()的静态方法(在调用collect之前的最后一个流转换的类型,在此示例中为Choice)。

Map<String, Choice> map = choices.stream().collect(Collectors.toMap(Choice::getString, Function.identity());

答案 3 :(得分:0)

Map map = list1.stream()。collect(() - &gt; new HashMap(),(r,s) - &gt; r.put(s.getString(),s),(r,s) - &gt; r.putAll(s));