使用groupingBy创建一个包含不可变列表的Map作为键

时间:2017-10-13 11:10:11

标签: java java-8

说,我有一个名为Project的课程,

class Project {
    private String projectId;
    private String projectName;
}

和一个名为Employee的类,它有一个项目列表

class Employee {
    private String name;
    private List<Project> projects
}

我还有一个Employee对象列表。现在,我需要创建一个Map,其中项目列表作为键,一组员工对象作为此列表中的值。我可以通过

来实现它
Map<List<Project>, Set<Employee>> x =
        employees
        .stream
        .collect(Collectors.groupingBy(Employee::getProjects, Collectors.toSet()));

但是,由于我使用List作为键,我想要格外小心并确保列表是不可变的。有没有办法实现这个目标?

感谢。

5 个答案:

答案 0 :(得分:2)

Java 9支持列表不变性。您只需将Employee#getProjects更改为以下内容:

public List<Project> getProjects() {
    return List.of(projects.toArray(new Project[projects.size()]));
}

如果您不希望此方法返回不可变List,那么您可以更改Collector

employees.stream()
         .collect(Collectors.groupingBy(e -> List.of(e.getProjects().toArray(new Project[0])), Collectors.toSet()));

答案 1 :(得分:1)

如果我没有遗漏这里显而易见的事情,你不能简单地将其包含在Collections.unmodifiableList中:

 collect(Collectors.groupingBy(
          emps -> Collections.unmodifiableList(emps.getProjects()), 
          Collectors.toSet());

如果您在类路径上有guava,则可以使用ImmutableList

答案 2 :(得分:0)

这就是你用Guava做的事情(我试用了版本24.1,这是迄今为止的最新版本)

List<Employee> employees = new ArrayList<>();

//  ... let's assume someone fills in the employees

// Everything mutable
Map<List<Project>, Set<Employee>> x =
    employees
        .stream()
        .collect(Collectors.groupingBy(Employee::getProjects, Collectors.toSet()));

// Everything immutable
ImmutableMap<ImmutableList<Project>, ImmutableSet<Employee>> immutableX =
    employees
        .stream()
        .collect(
            Collectors.collectingAndThen(
                Collectors.groupingBy(
                    (employee) -> ImmutableList.copyOf(employee.getProjects()),
                    ImmutableSet.<Employee>toImmutableSet()),
                ImmutableMap::copyOf));

// Only the List<Project> immutable
Map<ImmutableList<Project>, Set<Employee>> immutableListX =
    employees
        .stream()
        .collect(
            Collectors.groupingBy(
                (employee) -> ImmutableList.copyOf(employee.getProjects()),
                Collectors.toSet()));

这假设您的类定义是这些(我需要为原始示例添加getProjects方法进行编译):

class Project {
  public String projectId;
  public String projectName;
}

class Employee {
  public String name;
  public List<Project> projects;

  public List<Project> getProjects() {
    return projects;
  }
}

答案 3 :(得分:-1)

您可以使用

private List<? extends Project> projects = new LinkedList<>();

填充员工时。它建立了一个逻辑上不可变的列表。

答案 4 :(得分:-1)

如果您不介意将地图初始存储在可变地图中,然后将其复制到不可变集合中,则可以执行以下操作:

ImmutableMap<List<Project>, List<Employee>> collect = employees.stream()
            .collect(Collectors.collectingAndThen(Collectors.groupingBy(Employee::getProjects),
                    ImmutableMap::copyOf));

ImmutableMap是Google Common的结构( com.google.common.collect.ImmutableMap )。也归功于this