如何将List<T>转换为Map<String, T>而不是Map<String, List<T>>?

7

我遇到了这样的情况,需要将 List<Book> 转换为 Map<String, Book>,但是我找到的唯一解决方案是如何转换 Map<String, List<Book>>

该类本身的代码如下(我省略了 getters/setters 和 constructors):

public class Book {
    private String asin;
    private String author;
    private String title;
}

我希望通过某些唯一的键来映射所有的书籍,这样重复的概率要么可以忽略不计,要么为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)));

这段代码虽然能够运行,但是它看起来很丑陋,难以阅读并且不够优美,如果继续使用的话可能会让我的同事感到困惑。是否有更好的Java 8方法可以实现相同的结果呢?

3个回答

7

使用toMap代替groupingBy

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

如果您用于分组的键是唯一的,则没有理由使用 groupingBy

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

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

如果我的键不是唯一的,并且我决定取第一个元素,那么会有什么区别吗? - Dmytro Chasovskyi
@DmytroChasovskyi,在这种情况下,您需要添加一个合并函数。 - Eran
2
好的,我在回答时也在考虑这个问题。(a,b) -> a 是否保证 .get(0) - Naman
2
@nullpointer 嗯,我认为它比 .get(0) 更正确,因为 groupingBy 对于给定组的 List 中元素的顺序没有任何说明。.get(0) 可能会根据原始 List 的顺序返回或不返回与给定键匹配的第一本书。 - Eran
1
@Eran 看起来,groupingBy 保留了顺序。https://dev59.com/9VkT5IYBdhLWcg3wB7Es - Naman

4

如果您确定键是唯一的,那么您不需要对书籍进行分组。

Map<String, Book> booksByAsinAndTitle = books.stream()
    .collect(Collectors.toMap(book -> book.getAsin() + "||" + book.getTitle(), x -> x));

2
同样的内容,使用 Map.putIfAbsentforEach 更简单的表示方式如下:
Function<Book, String> primaryKey = book -> book.getAsin() + "||" + book.getTitle();
Map<String, Book> booksByAsinAndTitle = new HashMap<>();
books.forEach(book -> booksByAsinAndTitle.putIfAbsent(primaryKey.apply(book), book));

注意:这确保了针对某个键找到的第一个“book”对象始终留在映射表中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接