Как получить список значений из Map

Есть

Map<Person, List <Item>> mapOfPersons

Как получить List<Item> одного Person? У Person есть уникальный id.

Я не понимаю как мне достать person из Map по id. Я пробую делать нечто подобное:

mapOfPersons.get(mapOfPersons.entrySet().stream()
    .filter(x -> x.getKey().getId().equals(personId)
    .collect(Collectors.toList())
)

но возвращается null


Ответы (2 шт):

Автор решения: Nowhere Man

Можно либо искать ключ типа Person, соответствующий заданному id:

List<Item> itemsForId = mapOfPersons.get(
    mapOfPersons.keySet().stream() // Stream<Person>
        .filter(p -> Objects.equals(personId, p.getId()))
        .findFirst() // Optional<Person>
        //.get()     // вернуть по personId, может быть NoSuchElementException
        .orElse(null) // вернуть null, если personId не найден
);

Здесь в случае использования Optional.get может быть выброшено NoSuchElementException, если не будет найден ключ по заданному personId. Если воспользоваться orElse(null), то в зависимости от разновидности мапы может быть выброшено NullPointerException.

Поэтому может быть безопаснее сразу искать требуемый список через стрим Map.Entry:

List<Item> itemsForId = mapOfPersons.entrySet()
        .stream() // Stream<Map.Entry<Person, List<Item>>>
        .filter(e -> Objects.equals(personId, e.getKey().getId()))
        .map(Map.Entry::getValue) // Stream<List<Item>>
        .findFirst() // Optional<List<Item>>
        .orElse(null); // вернуть null, если personId не найден
→ Ссылка
Автор решения: insolor

Переопределяем в Person методы hash и equals так, чтобы равенство проверялось по полю id

public class Person {
    private final long id;
    private String name = null;

    public Person(long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Person(long id) {
        this.id = id;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return id == person.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    @Override
    public String toString() {
        return String.format("Person(id=%d, name='%s')", id, name);
    }
}
public class Item {
    private final String name;

    public Item(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return String.format("Item(name='%s'", name);
    }
}

Далее, когда нужно получить значение по Person с нужным id, создаем новый объект Person с этим id, и просто через get получаем значение:

Map<Person, List<Item>> mapOfPersons = new HashMap<>();
Person person1 = new Person(1, "Person 1");
Person person2 = new Person(2, "Person 2");
mapOfPersons.put(person1, Arrays.asList(new Item("Item 11"), new Item("Item 12")));
mapOfPersons.put(person2, Arrays.asList(new Item("Item 21"), new Item("Item 22")));

System.out.println(mapOfPersons.get(new Person(1)));
System.out.println(mapOfPersons.get(new Person(2)));

Вывод:

[Item(name='Item 11', Item(name='Item 12']
[Item(name='Item 21', Item(name='Item 22']

Если Person более сложный объект (если в нем больше чем пара полей), то имеет смысл в Map в качестве ключей использовать не объект целиком, а просто id.

→ Ссылка