使用Stream API并合并嵌套列表

8
假设我有一个“Shelf”类,每个“Shelf”都有多本“Book”。
public class Shelf{
   private String shelfCode;
   private ArrayList<Book> books; //add getters, setters etc.
}

public class Book{
  private String title;
}

现在假设我有一个方法返回一个包含若干书籍的Shelf列表。如何使用stream将这些书籍全部收集到一个列表中?
List<Shelf> shelves = new ArrayList<Shelf>();

Shelf s1 = new Shelf();
s1.add(new Book("book1"));
s1.add(new Book("book2"));

Shelf s2 = new Shelf();
s1.add(new Book("book3"));
s1.add(new Book("book4"));

shelves.add(s1);
shelves.add(s2);

List<Book> booksInLibrary = //??

我在考虑类似于

List<Book> booksInLibrary = 
      shelves.stream()
             .map(s -> s.getBooks())
             .forEach(booksInLibrary.addall(books));

但似乎它并不起作用,会抛出编译错误。

1个回答

15
你可以使用flatMap来实现这个。
shelves.stream()
       .flatMap(s -> s.getBooks().stream())
       .collect(Collectors.toList());

流处理过程非常简单: s -> s.getBooks().stream()为每个书架上的每本书创建一个流,flatMap将它们扁平化,collect(Collectors.toList())将结果存储在列表中。


6
实际上,每当你考虑在流上使用 forEach() 时,请退一步并问自己,“这真的是最好的方法吗?”然后用“啊,当然不是”来回答自己。 - Kayaman
3
我认为你需要在这个示例中添加一个 map 步骤来获取书架对象的书籍属性。 - Jeroen Steenbeeke
3
是的,应该是 flatMap(s -> s.getBooks().stream()) - Kayaman
https://www.mkyong.com/java8/java-8-flatmap-example/ 这里有更多优秀的示例和对 flatMap 工作原理的良好解释。 - kalgecin
1
使用方法引用的略微不同的方法如下:shelves.stream().map(Shelf::getBooks).flatMap(List::stream) .collect(Collectors.toList()); - Ousmane D.

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