Java 8 Collectors to Map

1. 介绍

在本教程中,咱们将讨论Collectors类的toMap()方法。咱们使用它将流收集到一个Map实例中。java

对于本教程中涉及的全部示例,咱们将使用图书列表做为数据源,并将其转换为不一样的Map实现。git

2. List 转换 Map

咱们将从最简单的状况开始,将List 转换 Mapgithub

Book类定义以下:web

class Book { private String name; private int releaseYear; private String isbn; //getters and setters } 复制代码

接着,咱们将建立一个List<Book>来验证咱们的代码:api

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")); 复制代码

对于这个场景,咱们将使用如下重载的toMap()方法:app

Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) 复制代码

使用Collectors.toMap(), 咱们将会获得一个Map<String,String>,其中key是isbn的值,value为name的值。ide

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);//true } 复制代码

3. 解决 Key 的冲突

上面的例子运行得很好,可是若是有一个重复的key会发生什么呢?post

让咱们来想象一下,咱们将每本图书的出版年份做为key,转换到Map<Integer, Book>中。单元测试

public Map<Integer, Book> listToMapWithDupKeyError(List<Book> books) { return books.stream().collect(Collectors.toMap(Book::getReleaseYear, Function.identity())); } 复制代码

鉴于咱们上面的例子,咱们会看到一个IllegalStateException的异常:

@Test(expected = IllegalStateException.class) public void whenMapHasDuplicateKey_without_merge_function_then_runtime_exception() { convertToMap.listToMapWithDupKeyError(bookList); } 复制代码

要解决这个问题,咱们须要使用另外一种toMap()方法,附加一个参数,mergeFunction:

Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction) 复制代码

让咱们引入一个merge函数,它代表,在发生冲突的状况下,咱们保留现有的元素:

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()方法将返回一个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

让咱们以上面的例子为例,添加一个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. List 转换 SortedMap

最后,让咱们看看如何返回一个排序后的Map。为此,咱们须要对List<Book>进行排序,并使用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)); } 复制代码

上面的代码将List<Book>按照书名进行排序,而后将结果收集到TreeMap<String, Book>中:

@Test public void whenMapisSorted() { assertTrue(convertToMap.listToSortedMap(bookList).firstKey().equals("The Fellowship of the Ring")); } 复制代码

5. 结论

在本文中,咱们研究了Collectors类的toMap()方法。它容许咱们从一个流建立一个新的Map。咱们还学习了如何解决key冲突和建立不一样的Map实现。

代码能够在GitHub中找到。

原文连接:www.baeldung.com/java-collec…

做者:Rodrigo Graciano

译者:李东

 

做者:锅外的大佬 连接:https://juejin.im/post/5d06f11b5188252a71629c7b 来源:掘金 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。
相关文章
相关标签/搜索