Java 8发布后分组

时间:2016-02-03 00:18:23

标签: java grouping java-stream

我有一个Job类对象列表,每个对象都有一个标签集合(网络),这个集合是可变的,对hashCode和对象没有影响。

我需要做的是获取所有唯一Job对象的列表,并且对于每个这样的对象组合所有标签,例如,我有一个列表:

Car truck = new car();

这应该减少到[{position: "CTO", dates: "2012-2014", city: "New York", networks: ["foo"]}, {position: "CTO", dates: "2012-2014", city: "New York", networks: ["bar"]}]

[{position: "CTO", dates: "2012-2014", city: "New York", networks: ["foo", "bar"]}]

这是实际的Job类代码,这就是我实现此操作的方式:

public class Job {
    private final String position;
    private final String dates;
    private final Integer startYear;
    private final Integer endYear;
    private final String city;
    private Set<NetworkType> networks;

    public String getPosition() {
        return position;
    }

    public String getDates() {
        return dates;
    }

    public String getCity() {
        return city;
    }

    public Set<NetworkType> getNetworks() {
        return networks;
    }

    public void setNetworks(Set<NetworkType> networks) {
        this.networks = networks;
    }

    public Integer getStartYear() {
        return startYear;
    }

    public Integer getEndYear() {
        return endYear;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Job)) {
            return false;
        }
        Job job = (Job) o;
        return Objects.equals(position, job.position) &&
                Objects.equals(dates, job.dates) &&
                Objects.equals(city, job.city);
    }

    @Override
    public int hashCode() {
        return Objects.hash(position, dates, city);
    }
}

但是我觉得这个代码非常糟糕,特别是因为我在流中使用了外部地图,我想知道有没有办法在没有中间转换的情况下在一个链中做到这一点。 对于我实现此功能的任何有效批评,我将不胜感激。 谢谢!

1 个答案:

答案 0 :(得分:2)

假设我们将所有networks合并到我们找到的特定Job第一次出现中,我们可以在一个(相当复杂的)行中执行此操作:

import static java.util.stream.Collectors.*;
import static java.util.function.Function.identity;

Map<Job, Optional<Job>> collect = jobs.stream()
    .collect(groupingBy(identity(), reducing((l, r) -> {
        l.networks().addAll(r.networks());
        return l;
    })));

我使用了流畅的访问器,因为我不能打扰get

因此。这是如何工作的?

首先我们stream jobs并致电Collectors.groupingBy上的Function.identity(),这会给我们一个Map<Job, List<Job>>

但我们不想要List<Job> - 这是Collectors.reducing的来源。这是作为Collector的下游groupingBy传递的。

下游Collector负责创建Map的值部分 - 在这种情况下,我们将所有找到的作业减少为<{1}}。< / p>

Job

所以这需要两个reducing((l, r) -> { l.networks().addAll(r.networks()); return l; } 个项目,然后返回一个。它是折叠操作,因此Job依次为每个BiFunction return值。我们所做的就是将新Job中的所有networks()添加到现有Job

显然这会给你一个Job,但崩溃是一项简单的工作。

我看不到直接将其变成Map<String, Optional<Job>>的方法......

为了将List处理为Map<Job, Optional<Job>>,可以使用以下内容:

List<Job>

所以,你可以在一行中完成所有工作:

collect.values().stream()
    .map(Optional::get)
    .collect(toList);

虽然这样做的可读性值得怀疑。