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 來源:掘金 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索