如何创建List <T>到Map <String,T>而不是Map <String,List <T >>?

Dmy*_*kyi 7 java java-8 java-stream

我用的情况下遇到的,当我需要转换List<Book>Map<String, Book>和唯一的解决办法我能找到的是怎么做的Map<String, List<Book>>.

类本身看起来如下(我省略了getter/setters和构造函数):

public class Book {
    private String asin;
    private String author;
    private String title;
}
Run Code Online (Sandbox Code Playgroud)

我希望通过某些唯一的密钥映射所有书籍,因此重复的可能性要么是可忽略的,要么是0.

我试着这样做:

    Map<String, Book> booksByAsinAndTitle = books.stream()
        .collect(Collectors.groupingBy((book) -> book.getAsin() + "||" + book.getTitle()))
        .entrySet()
        .stream()
        .collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue().get(0)));
Run Code Online (Sandbox Code Playgroud)

它可以工作,但它看起来很难看,几乎不可读,并且在代码库中不太好,因为它可能会让我的同事感到困惑.有没有更好的方法java 8来达到相同的结果?

Era*_*ran 7

使用toMap而不是groupingBy:

Map<String, Book> booksByAsinAndTitle = 
    books.stream()
         .collect(Collectors.toMap(b -> b.getAsin() + "||" + b.getTitle(),
                                   Function.identity()));
Run Code Online (Sandbox Code Playgroud)

如果您要分组的密钥是唯一的,则没有理由使用groupingBy.

如果您的密钥可能不是唯一的,并且您仍希望Map包含与给定密钥匹配的第一个值,请添加合并功能:

Map<String, Book> booksByAsinAndTitle = 
    books.stream()
         .collect(Collectors.toMap(b -> b.getAsin() + "||" + b.getTitle(),
                                   Function.identity()),
                                   (a,b) -> a);
Run Code Online (Sandbox Code Playgroud)

  • 好吧,我在发布我的答案的同时也在思考它.`(a,b) - > a`保证`.get(0)`? (2认同)
  • @nullpointer好吧,我认为它比.get(0)更正确,因为groupingBy没有说明给定组列表中元素的顺序..get(0)可能会也可能不会返回与给定键匹配的第一本书(根据原始列表的顺序). (2认同)