为什么在以下代码段中流过滤器不起作用

时间:2018-10-16 00:53:38

标签: java java-8 java-stream

考虑下面的代码片段,它给出了null;您能帮忙吗?

//model class
public class Author {
    private String name;
    private int countOfBooks;
    // setters and getters left for brevity
}

//model class
public class Book {
    private String name;
    private int year;
    private Author author;
    // setters and getters left for brevity
}

现在,让我们说,我们要过滤过滤掉2005年或之前出版的书籍。我们可能会两次<过滤>过滤,如下所示:

// main class 
public static void main(String[] args) {
    List<Author> authors = Arrays.asList(new Author("Venkat", 10),new Author("Richord", 8));

    List<Book> books = Arrays.asList(new Book("Venkat", 2006, new Author()));

    books.stream()
         .filter(book -> book.getYear() > 2005)  // filter out books published in or before 2005
         .map(Book::getAuthor)                   // get the list of authors for the remaining books
         .filter(Objects::nonNull)               // remove null authors from the list
         .map(Author::getName)                   // get the list of names for the remaining authors
         .forEach(System.out::println);          // print the value of each remaining element
}

2 个答案:

答案 0 :(得分:0)

如果您查看books.stream()上的情况,您会发现在某种特殊情况下,您的书的所有作者都将得到聘用:

.map(Book::getAuthor)              // get the list of authors for the remaining books

但是,在声明books中,您声明的书是这样的:

List<Book> books = Arrays.asList(
            new Book("Venkat",2006,new Author())
    );

根据您的课程声明,这将创建一本书的标题为“ Venkat”,年份为“ 2006”。对于本书的作者,您没有参数地调用了new Author()。根据您对author的类声明,这将创建一个名称为null且countOfBooks为null的作者。

相反,您的图书声明应该类似于:

List<Book> books = Arrays.asList(
            new Book("Venkat",2006,authors[0])
    );

OR

List<Book> books = Arrays.asList(
            new Book("Venkat",2006,new Author("Sekhar", 1))
    );

答案 1 :(得分:0)

您要尝试的示例打算打印年份大于2005年的书籍的作者姓名。这需要一些示例数据-混合年份的书籍(目的是根据年份过滤某些数据)和具有名称的作者

有两个类:AuthorBook。让我们为它们创建一些示例数据:


作者:

作者具有两个属性-名称,书数。让我们创建两个作者对象。请注意作者的名字:

  • name =“ H. G. Wells”,簿记= 2。
  • name =“ Harper Lee”,簿记= 1。


图书:

书具有三个属性-名称,年份和作者。让我们创建三个书本对象:

  • name =“世界大战”,年份= 1898,作者=“ H. G. Wells”( 上面创建的作者:1)。
  • name =“ The Time Machine”,年份= 1895,作者=“ H. G. Wells”( 上面创建的作者:1)。
  • name =“ To Kill a Mockingbird”,年份= 1960,作者=“ Harper Lee”(作者在上面创建:2)。


现在,构建Author对象:

Author hgWells = new Author("H. G. Wells", 2);
Author hLee = new Author("Harper Lee", 1);

注意:也可以使用以下构造函数来构建Author对象:

Author hgWells = new Author();

这将构建一个作者对象,其名称值为null,帐簿数量值为zero。这些nullzeroAuthor类中定义的实例变量的默认值。因此,对getName()方法的调用将返回null


还有一些Book对象:

Book book1 = new Book("War of the Worlds", 1898, hgWells);
Book book2 = new Book("The Time Machine", 1895, hgWells);
Book book3 = new Book("To Kill a Mockingbird", 1960, hLee);


创建书籍列表:

List<Book> books = Arrays.asList(book1, book2, book3);
System.out.println(books);

这将打印:

[(War of the Worlds, 1898 - H. G. Wells), (The Time Machine, 1895 - H. G. Wells), (To Kill a Mockingbird, 1960 - Harper Lee)]

请注意,被覆盖的Object的{​​{1}}方法显示了toString()对象的所有属性详细信息。


过滤书籍:

现在,我们有一些带有作者数据的书可供使用。让我们过滤它们。在此示例中,我将印刷20世纪的书籍(即,在1900年至1999年之间出版的过滤器书籍出版年份大于1899年;我们只有19世纪和20世纪的书籍)。

由于我们正在使用流;过滤器将成为lambda。在这里:

Book

让过滤器应用于书籍列表:

Predicate<Book> yearFilter = book -> book.getYear() > 1899;

这将打印: Harper Lee 。在20世纪只有一本书出版年份-1960年,并印有作者的名字。

评论:

这是一个示例,用于创建一些测试数据并将其用于流的过滤器功能。


代码:

books.stream()
    .filter(yearFilter)
    .map(book -> book.getAuthor().getName())
    .forEach(authorName -> System.out.println(authorName));