1.概述
Collectors类的toMap()方法。 我们将使用它来将Streams收集到Map实例中。
2.List转Map
从最简单的情况开始,将List转换为Map。
定义Book类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
private String name;
private int releaseYear;
private String isbn;
}
创建书清单
List<Book> bookList = new ArrayList<>();
bookList.add(new Book("java8实战", 2013, "0395489318"));
bookList.add(new Book("spring实战", 2013, "0345339711"));
bookList.add(new Book("springboot实战", 2015, "0618129111"));
在这种情况下,将使用toMap()方法的以下重载:
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper)
使用toMap,可以指出如何获Map 的key和value的策略:
public Map<String, String> listToMap(List<Book> books) {
return books.stream().collect(Collectors.toMap(Book::getIsbn, Book::getName));
}
@Test
public void whenConvertFromListToMap() {
Map<String, String> map=listToMap(bookList);
System.out.println(map);//{0395489318=java8实战, 0618129111=springboot实战, 0345339711=spring实战}
assertEquals(3, listToMap(bookList).size());
}
3.解决Key冲突
假设按每本书的发行年份确定了Map的key:
public Map<Integer, Book> listToMapWithDupKeyError(List<Book> books) {
return books.stream().collect(
Collectors.toMap(Book::getReleaseYear, Function.identity()));
}
@Test(expected = IllegalStateException.class)
public void whenMapHasDuplicateKey() {
Map<Integer, Book> integerBookMap = listToMapWithDupKeyError(bookList);
System.out.println(integerBookMap);
}
要解决此问题,需要使用带有附加参数mergeFunction的其他方法:
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction)
介绍一个合并函数,该函数指示在发生冲突的情况下,保留现有条目:
public Map<Integer, Book> listToMapWithDupKey(List<Book> books) {
return books.stream().collect(Collectors.toMap(Book::getReleaseYear, Function.identity(),
(existing, replacement) -> existing));
}
@Test
public void whenMapHasDuplicateKeyThenMergeFunctionHandlesCollision() {
Map<Integer, Book> booksByYear = listToMapWithDupKey(bookList);
System.out.println(booksByYear);//{2013=Book(name=java8实战, releaseYear=2013, isbn=0395489318), 2015=Book(name=springboot实战, releaseYear=2015, isbn=0618129111)}
assertEquals(2, booksByYear.size());
assertEquals("0395489318", booksByYear.get(2013).getIsbn());
}
4.其他Map类型
默认情况下,toMap()方法将返回HashMap。
但是可以返回不同的Map实现:
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier)
其中的mapSupplier是一个函数,该函数返回带有结果的新的空Map。
4.1. List 转ConcurrentMap
public Map<Integer, Book> listToConcurrentMap(List<Book> books) {
return books.stream().collect(Collectors.toMap(Book::getReleaseYear, Function.identity(),
(o1, o2) -> o1, ConcurrentHashMap::new));
}
@Test
public void whenCreateConcurrentHashMap() {
assertTrue(listToConcurrentMap(bookList) instanceof ConcurrentHashMap);
}
4.2Sorted Map
如何返回排序后的Map。 将使用TreeMap作为mapSupplier参数。
public TreeMap<String, Book> listToSortedMap(List<Book> books) {
return books.stream()
.collect(
Collectors.toMap(Book::getName, Function.identity(), (o1, o2) -> o1, TreeMap::new));
}
@Test
public void whenMapisSorted() {
TreeMap<String, Book> treeMap = listToSortedMap(bookList);
System.out.println(treeMap);
//{java8实战=Book(name=java8实战, releaseYear=2013, isbn=0395489318), springboot实战=Book(name=springboot实战, releaseYear=2015, isbn=0618129111), spring实战=Book(name=spring实战, releaseYear=2013, isbn=0345339711)}
assertEquals("java8实战", treeMap.firstKey());
}