Java 8 Collectors to Map
1. 介紹
在本教程中,我們將討論Collectors
類的toMap()
方法。我們使用它將流收集到一個Map
例項中。
對於本教程中涉及的所有示例,我們將使用圖書列表作為資料來源,並將其轉換為不同的Map
實現。
2. List 轉換 Map
我們將從最簡單的情況開始,將List
轉換 Map
。
Book
類定義如下:
class Book {
private String name;
private int releaseYear;
private String isbn;
//getters and setters
}
複製程式碼
接著,我們將建立一個List<Book>
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()
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的值。
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會發生什麼呢?
讓我們來想象一下,我們將每本圖書的出版年份作為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
來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處