Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/394.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用groupingBy创建以不可变列表为键的映射_Java_Java 8 - Fatal编程技术网

Java 使用groupingBy创建以不可变列表为键的映射

Java 使用groupingBy创建以不可变列表为键的映射,java,java-8,Java,Java 8,我有一门课叫Project class Project { private String projectId; private String projectName; } 还有一个名为Employee的类,它有一个项目列表 class Employee { private String name; private List<Project> projects } class员工{ 私有字符串名称; 私人清单项目 } 我还有一个员工对象列表。现在,

我有一门课叫Project

class Project {
    private String projectId;
    private String projectName;
}
还有一个名为Employee的类,它有一个项目列表

class Employee {
    private String name;
    private List<Project> projects
}
class员工{
私有字符串名称;
私人清单项目
}
我还有一个员工对象列表。现在,我需要创建一个映射,其中项目列表作为键,一组employee对象作为该列表中的值。我可以让它工作

Map<List<Project>, Set<Employee>> x =
        employees
        .stream
        .collect(Collectors.groupingBy(Employee::getProjects, Collectors.toSet()));
Map x=
员工
流动
.collect(Collectors.groupingBy(Employee::getProjects,Collectors.toSet());
然而,由于我使用列表作为键,所以我要格外小心,确保列表是不可变的。有没有办法做到这一点

谢谢

您可以使用

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

private List如果您不介意将映射最初存储在可变映射中,然后复制到不可变集合中,您可以执行以下操作:

ImmutableMap<List<Project>, List<Employee>> collect = employees.stream()
            .collect(Collectors.collectingAndThen(Collectors.groupingBy(Employee::getProjects),
                    ImmutableMap::copyOf));
public List<Project> getProjects() {
    return List.of(projects.toArray(new Project[projects.size()]));
}
ImmutableMap collect=employees.stream()
.collect(Collectors.collectingAndThen(Collectors.groupingBy(Employee::getProjects)),
ImmutableMap::copyOf));

ImmutableMap是Google公共结构(com.Google.Common.collect.ImmutableMap)。也要归功于。Java 9支持列表不变性。您只需将
Employee#getProjects
更改为以下内容:

ImmutableMap<List<Project>, List<Employee>> collect = employees.stream()
            .collect(Collectors.collectingAndThen(Collectors.groupingBy(Employee::getProjects),
                    ImmutableMap::copyOf));
public List<Project> getProjects() {
    return List.of(projects.toArray(new Project[projects.size()]));
}

如果我没有遗漏一些明显的东西,你能不能简单地将其包装到
集合中。不可修改列表

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

另一方面,如果类路径上有
guava
,则可以使用
ImmutableList

这就是使用它的方法(我使用了24.1版,这是今天最新的版本)

List employees=new ArrayList();
//  ... 让我们假设有人填补了员工的空缺
//一切都是可变的
地图x=
员工
.stream()
.collect(Collectors.groupingBy(Employee::getProjects,Collectors.toSet());
//万物不变
ImmutableMap immutableX=
员工
.stream()
.收集(
收藏,收藏,然后(
收集者分组(
(employee)->ImmutableList.copyOf(employee.getProjects()),
ImmutableSet.toImmutableSet()),
ImmutableMap::copyOf));
//只有列表是不可变的
映射不可变列表=
员工
.stream()
.收集(
收集者分组(
(employee)->ImmutableList.copyOf(employee.getProjects()),
Collectors.toSet());
这假设您的类定义如下(我需要为原始示例添加getProjects方法进行编译):

类项目{
公共字符串投影;
公共字符串projectName;
}
班级员工{
公共字符串名称;
公开项目清单;
公共列表项目(){
返回项目;
}
}

@tobias_k这并不能真正解决问题,因为可以调用
employee.getProjects().add(newProject)。我建议改为:
e->Collections.unmodifiableList(新的ArrayList(e.getProjects())
,即一个单独的副本。我认为您只需要制作一个防御性副本。可能有一种方法可以实现您的目标,而无需使用
映射
。实际上,您应该详细说明为什么希望列表是不可变的。是否要防止映射的用户意外修改employee对象内的列表,还是要确保哈希不会更改,并且您可以从映射中实际检索员工集?根据你的关注点,最好的解决方案可能会有所不同。@tobias_k-是后者。当我在地图上执行get()时,我不希望有人更改哈希值,从而导致意外行为。我不认为他将java-8标记为java-9答案though@PaulLemarchand或者他/她所说的标签是指“Java8或更高版本”。你认为这为什么会使列表键不可变?我错了。我的印象是,映射的不变性将推断它包含的键/值对本身是不可变的。通过测试,我可以清楚地看到,虽然在地图中添加新条目有限制,但在员工列表中添加新员工没有任何限制@谢谢你的关注!
class Project {
  public String projectId;
  public String projectName;
}

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

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