Collectors.toMap () keyMapper - більш стислий вираз?


77

Я намагаюся придумати більш стислий вираз для параметра функції "keyMapper" у наступному Collectors.toMap()виклику:

List<Person> roster = ...;

Map<String, Person> map = 
    roster
        .stream()
        .collect(
            Collectors.toMap(
                new Function<Person, String>() { 
                    public String apply(Person p) { return p.getLast(); } 
                },
                Function.<Person>identity()));

Здається, я мав би змогу вбудувати його за допомогою лямбда-виразу, але я не можу придумати такого, який компілює. (Я досить новачок у лямбда, тому це не є великим сюрпризом.)

Дякую.

-> Оновлення:

Як зазначено у прийнятій відповіді

Person::getLast

це те, що я шукав, і це те, що я спробував. Однак проблема полягала в нічній збірці Eclipse 4.3 BETA_8 - вона позначила це як неправильну. Під час компіляції з командного рядка (що я повинен був зробити перед публікацією), він спрацював. Отже, час подати помилку на eclipse.org.

Дякую.


1
Зверніть увагу також, що статичний імпорт для Collectors.toMap зробить вираз ще коротшим, проте NetBeans, схоже, не імпортує їх для мене, однак.
Бретт Райан,

Просто наткнувся на це питання. Вашою проблемою була не тільки Eclipse 4.3, це також була JDK 8 до u112, яка мала подібні проблеми. HTH.
Бен

Відповіді:


189

Ви можете використовувати лямбду:

Collectors.toMap(p -> p.getLast(), Function.identity())

або, коротше, ви можете використовувати посилання на метод, використовуючи :::

Collectors.toMap(Person::getLast, Function.identity())

і замість Function.identity, ви можете просто використовувати еквівалент лямбда:

Collectors.toMap(Person::getLast, p -> p)

Якщо ви використовуєте Netbeans, ви повинні отримувати підказки щоразу, коли анонімний клас може бути замінений лямбда.


2
Ви можете зробити свої вирази ще коротшими, видаливши дужки, оскільки вони не потрібні для окремих аргументів, тобто Collectors.toMap(Person::getLast, p -> p).
Бретт Райан,

1
Я також впевнений, що аргумент типу для функції ідентичності не потрібен, оскільки це можна зробити висновок. Collectors.toMap(Person::getLast, Function.identity())
GuiSim

@GuiSim Я думаю, що зараз це справді так - це була помилка в попередніх версіях Java 8.
assylias

2
Хе-хе, схоже, p -> p якось оптимізовано, жоден новий скомпільований анонімний клас не будується. Я думаю, він використовує Function.identity () внутрішньо, замість того, щоб створювати марний клас.
Vlasec

1
Важливе застереження! Якщо ваш Список містить нульові значення, ви отримаєте тут виняток через те, як реалізовано Collectors.toMap, навіть незважаючи на те, що карта з нульовими значеннями зазвичай цілком прийнятна. Звичайно, у цьому випадку ви все одно отримаєте NPE при доступі до Person :: getLast, але є багато інших випадків, коли ваш ключ може складатися інакше, але ви все одно отримаєте виняток. Дивіться stackoverflow.com/questions/24630963/…
Себастіан ван ден Брук,

29
List<Person> roster = ...;

Map<String, Person> map = 
    roster
        .stream()
        .collect(
            Collectors.toMap(p -> p.getLast(), p -> p)
        );

це був би переклад, але я не запускав цього або використовував API. швидше за все, ви можете замінити p -> p на Function.identity (). та статично імпортувати уMap (...)


Чи існує спосіб об’єднання подібних значень у List <Person> у випадку дублікатів замість їх згуртування?
Lovegiver

5

Ми можемо використовувати необов’язкову функцію злиття також у випадку зіткнення того самого ключа. Наприклад, якщо дві або більше осіб мають однакове значення getLast (), ми можемо вказати, як об’єднати значення. Якщо ми цього не зробимо, ми можемо отримати IllegalStateException. Ось приклад досягнення цього ...

Map<String, Person> map = 
roster
    .stream()
    .collect(
        Collectors.toMap(p -> p.getLast(),
                         p -> p,
                         (person1, person2) -> person1+";"+person2)
    );

1
Вибачте, але що це означає? (person1, person2) -> person1+";"+person2)
Thach Huynh

1
Якщо відображені ключі містять дублікати (відповідно до Object.equals (Object)), функція відображення значень застосовується до кожного рівного елемента, а результати об'єднуються за допомогою наданої функції злиття. Будь ласка, зверніться до посилання docs.oracle.com/javase/8/docs/api/java/util/stream/…
KayV
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.