Использование groupingBy для создания Карты с неизменяемым списком в качестве ключа

Скажем, у меня есть класс под названием Project,

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

и класс Employee, который имеет список проектов

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

У меня также есть список объектов Employee. Теперь мне нужно создать карту со списком проектов как ключ и набор объектов-сотрудников в качестве значения из этого списка. Я могу заставить его работать с помощью

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

Однако, поскольку я использую List в качестве ключа, я хочу быть более осторожным и следить за тем, чтобы список был неизменным. Есть ли способ достичь этого?

Спасибо.

Ответ 1

Непрерывность списка поддерживается в 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()));

Ответ 2

Если я не пропущу что-то очевидное здесь, не можете ли вы просто обернуть это в Collections.unmodifiableList:

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

Если у вас есть guava на пути к классу, с другой стороны, вы можете использовать ImmutableList

Ответ 3

Вы можете использовать

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

при заполнении сотрудников. Он устанавливает логически неизменный список.

Ответ 4

Если вы не возражаете, чтобы ваша карта была первоначально сохранена в измененной карте и затем скопирована в неизменяемую коллекцию, вы можете сделать что-то вроде следующего:

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

The ImmutableMap - это структура Google Common (com.google.common.collect.ImmutableMap). Кредиты .