StreamAPI 的 Collectors.toMap 方法

基础语法

// 实现 1
public static <T, K, U>
    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper)
// 实现 2
public static <T, K, U>
    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper,
                                    BinaryOperator<U> mergeFunction)
// 实现 3
public static <T, K, U, M extends Map<K, U>>
    Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                                Function<? super T, ? extends U> valueMapper,
                                BinaryOperator<U> mergeFunction,
                                Supplier<M> mapSupplier)

由于最终返回的是一个 Map 对象,因此我们需要在 Collectors.toMap() 方法中定义 key、value 的映射关系。对应着实现 1 中的 keyMapper 和 valueMapper。

实现 2 中多了 mergeFunction 参数,为 key 重复时提供的合并方式,默认情况下,将会抛出 IllegalStateException 异常。

实现 3 中多了 mapSupplier 参数,用于指定返回的 Map 类型,默认是 HashMap。

实践案例

@AllArgsConstructor
@Data
public class Person {
    Integer id;
    String name;

    public static void main(String[] args) {
        List<Person> list = Stream.of(
                new Person(1, "John"),
                new Person(2, "Shellby"),
                new Person(3, "Tommy"),
                new Person(3, "Jerry")
        ).collect(Collectors.toList());

        Map<Integer, Person> collect = list.stream().collect(Collectors.toMap(k -> k.getId(), Function.identity(), (v1, v2) -> v1));
        Map<Integer, Person> collect1 = list.stream().collect(Collectors.toMap(k -> k.getId(), v -> v, (v1, v2) -> v1));
        Map<Integer, String> collect2 = list.stream().collect(Collectors.toMap(k -> k.getId(), v -> v.getName(), (v1, v2) -> v2));
        System.out.println(collect);
        System.out.println(collect1);
        System.out.println(collect2);

		System.out.println("----------------------------------------------------------------");

        // 指定返回的 Map 类型:适合一些特殊的场景,比如需要返回的数据是有序的,则可以采用 LinkedHashMap
        LinkedHashMap<Integer, Person> collect3 = list.stream()
                .collect(Collectors.toMap(k -> k.getId(), Function.identity(), (v1, v2) -> v1, LinkedHashMap::new));
        System.out.println(collect3);
        collect3.forEach((k, v) -> System.out.println(v));
    }
}

输出结果:

{1=Person(id=1, name=John), 2=Person(id=2, name=Shellby), 3=Person(id=3, name=Tommy)}
{1=Person(id=1, name=John), 2=Person(id=2, name=Shellby), 3=Person(id=3, name=Tommy)}
{1=John, 2=Shellby, 3=Jerry}
----------------------------------------------------------------
{1=Person(id=1, name=John), 2=Person(id=2, name=Shellby), 3=Person(id=3, name=Tommy)}
Person(id=1, name=John)
Person(id=2, name=Shellby)
Person(id=3, name=Tommy)

举例来说:

Map<Integer, Person> collect = list.stream().collect(Collectors.toMap(k -> k.getId(), v -> v, (v1, v2) -> v1));

k -> k.getId() 表示:采用 person 对象的 id 指作为 key 值。
v -> v 表示:采用原来的 person 对象作为 value 值。
(v1, v2) -> v1 表示:如果 key 值相同,则采用前一个 key 对应的 value 值作为最终的 value 值。

如果对返回的 Map 类型有要求,也可以进行自定义:

LinkedHashMap<Integer, Person> collect3 = list.stream()
                .collect(Collectors.toMap(k -> k.getId(), Function.identity(), (v1, v2) -> v1, LinkedHashMap::new));

此处,通过 LinkedHashMap::new 指定了返回的 Map 类型为 LinkedHashMap,适合要求返回的数据是有序的场景。