使用流(stream)操作时,很多场景会用到list.stream()…filter()…collect(Collectors.toMap())操作。
今天进入collections源码,看一下Collectors.toMap参数的含义。
Collectors.toMap()有多个重载方法。
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper) {
return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}
坑1
throwingMerger():遇到流中的重复key时,抛出异常,并打印key。(重复key抛异常)
默认new HashMap。
private static <T> BinaryOperator<T> throwingMerger() {
return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
}
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) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
自定义重复key处理策略
例:list.stream().collect(Collectors.toMap(Student::getId, Student::getName, (v1, v2) -> v1));
即遇到重复key时,value取先来的v1
默认new HashMap。
上面这两个重载方法其实调用的就是下面的这个:
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) {
BiConsumer<M, T> accumulator
= (map, element) -> map.merge(keyMapper.apply(element),
valueMapper.apply(element), mergeFunction);
return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}
参数KeyMapper:返回key的method,ex:(Book::getId)
参数valueMapper:返回value的method,ex:(Book::getName)
参数mergeFunction:遇到重复key时,处理策略,ex((v1,v2) -> v1)
Supplier mapSupplier:返回map/list的method,(HashMap::new/ConcurrentHashMap::new)
坑2
看其他文章说的,key为null也会导致异常,可自己试试。
解决办法:增加filter,过滤null key
bookList.stream().filter(book-> StringUtils.isNotEmpty(book.getId()))
.collect(Collectors.toMap(BookDTO::getId,book -> (book.getName()+book.getPrice())));