我遇到了需要将List<Book>
转换为Map<String, Book>
的情况,而我能找到的唯一解决方案是如何进行Map<String, List<Book>>
。
类本身看起来是这样的(我省略了getters / setter和构造函数):
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
来达到相同的结果?
答案 0 :(得分: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);
答案 1 :(得分:4)
如果您确定键是唯一的,则无需对书进行分组。
Map<String, Book> booksByAsinAndTitle = books.stream()
.collect(Collectors.toMap(book -> book.getAsin() + "||" + book.getTitle(), x -> x));
答案 2 :(得分:2)
使用Map.putIfAbsent
和forEach
的相同表示将更简单:
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
仍保留在地图中。