Java 8特性 - Collectors toMap
2019-06-14 本文已影响2人
老老戟
请关注订阅号: Rainbow Series
![](https://img.haomeiwen.com/i5945972/bcaf1af58f153e80.png)
1。介绍
在本快速教程中,我们将讨论Collectors类的tomap()方法。我们将使用它将流收集到映射实例中。
对于这里介绍的所有示例,我们将使用书籍列表作为起点,并将其转换为不同的映射实现。
2。list 转 map
我们将从最简单的情况开始,将列表转换为映射。
我们的书籍类定义为:
class Book {
private String name;
private int releaseYear;
private String isbn;
// getters and setters
}
我们将创建一个图书列表来验证我们的代码
List<Book> bookList = new ArrayList<>();
bookList.add(new Book("The Fellowship of the Ring", 1954, "0395489318"));
bookList.add(new Book("The Two Towers", 1954, "0345339711"));
bookList.add(new Book("The Return of the King", 1955, "0618129111"));
我们使用场景for this the following of the tomap(overload)法:
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper)
通过toMap,我们可以指示如何获取映射的键和值的策略:
public Map<String, String> listToMap(List<Book> books) {
return books.stream().collect(Collectors.toMap(Book::getIsbn, Book::getName));
}
我们可以很容易地验证它的工作原理:
@Test
public void whenConvertFromListToMap() {
assertTrue(convertToMap.listToMap(bookList).size() == 3);
}
解决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_without_merge_function_then_runtime_exception() {
convertToMap.listToMapWithDupKeyError(bookList);
}
要解决这个问题,我们需要使用另一种方法和附加参数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 = convertToMap.listToMapWithDupKey(bookList);
assertEquals(2, booksByYear.size());
assertEquals("0395489318", booksByYear.get(1954).getIsbn());
}
4. 其他 Map 类型
默认情况下,tomap()方法将返回哈希映射。
但是我们可以返回不同的映射实现吗?答案是肯定的
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier)
其中mapsupplier是返回带有结果的新空映射的函数。
4.1. List 转 ConcurrentMap
让我们以上面相同的例子,添加一个mapsupplier函数来返回一个concurrenthashmap
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(convertToMap.listToConcurrentMap(bookList) instanceof ConcurrentHashMap);
}
4.2. Sorted Map
最后,让我们看看如何返回已排序的映射。为此,我们需要对列表进行排序,并使用treemap作为mapsupplier参数:
public TreeMap<String, Book> listToSortedMap(List<Book> books) {
return books.stream()
.sorted(Comparator.comparing(Book::getName))
.collect(Collectors.toMap(Book::getName, Function.identity(), (o1, o2) -> o1, TreeMap::new));
}
上面的代码将根据图书名称对列表进行排序,然后将结果收集到TreeMap:
@Test
public void whenMapisSorted() {
assertTrue(convertToMap.listToSortedMap(bookList).firstKey().equals("The Fellowship of the Ring"));
}
5。结论
在本文中,我们研究了Collectors类的tomap()方法。它允许我们从流中创建一个新的映射。我们还学习了如何解决关键冲突和创建不同的映射实现