Java 8 Lambda表达式为何使用Function变量而不是内联的任何解释

时间:2019-04-27 23:09:10

标签: java lambda java-8 java-stream comparator

有人可以解释为什么我在以下代码中将lambda表达式放入Copmarator.compring()时不起作用。当我将相同的表达式提取到Function变量中时,它可以正常工作。

有两个示例(在Main.java类中),其中一个未编译(一个带有Optional),另一个正在编译,但在执行时抛出错误。我在注释中添加了无效代码,以表明将表达式提取到变量中后可以正常工作。

package com.slide;

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;

import static java.util.Comparator.*;
import static java.util.Comparator.reverseOrder;

public class Main {

    static class Book {
        private int price;
        private LocalDate date;
        private Author author;

        public Book(int price, LocalDate date, Author author) {
            this.price = price;
            this.date = date;
            this.author = author;
        }

        public int getPrice() { return price; }
        public void setPrice(int price) { this.price = price; }
        public LocalDate getDate() { return date; }
        public void setDate(LocalDate date) { this.date = date; }
        public Author getAuthor() { return author; }
        public void setAuthor(Author author) { this.author = author; }

        @Override
        public String toString() {
            String authorName = author != null && author.getName() != null ? author.getName() : "null";
            return "{ price : "
                    .concat(String.valueOf(price))
                    .concat(", year : ")
                    .concat(date != null ? date.toString() : "null")
                    .concat(", author : ")
                    .concat(authorName)
                    .concat("}");
        }
    }

    static class Author {
        private String name;

        public Author(String name) {
            this.name = name;
        }

        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    }

    static Author john = new Author("John");
    static Author marguerite = new Author("Marguerite");
    static Author charlton = new Author("Charlton");
    static Author gwen = new Author("Gwen");
    static Author marion = new Author("Marion");
    static Author mark = new Author("Mark");
    static Author jerry = new Author("Jerry");
    static Author bob = new Author("Bob");
    static Author dennis = new Author("Dennis");
    static Author mike = new Author(null);


    static Book b1 = new Book(15, LocalDate.of(1983, Month.JANUARY, 1), john);
    static Book b2 = new Book(8, LocalDate.of(1998, Month.AUGUST, 1), marguerite);
    static Book b3 = new Book(14, LocalDate.of(1992, Month.SEPTEMBER, 1), john);
    static Book b4 = new Book(10, LocalDate.of(2016, Month.MAY, 1), charlton);
    static Book b5 = new Book(10, LocalDate.of(1997, Month.FEBRUARY, 1), gwen);
    static Book b6 = new Book(8, LocalDate.of(1986, Month.AUGUST, 1), charlton);
    static Book b7 = new Book(54, LocalDate.of(1998, Month.MARCH, 1), john);
    static Book b8 = new Book(10, LocalDate.of(1997, Month.FEBRUARY, 1), marion);
    static Book b9 = new Book(32, LocalDate.of(2013, Month.JULY, 1), mark);
    static Book b10 = new Book(5, LocalDate.of(1997, Month.AUGUST, 1), jerry);
    static Book b11 = new Book(10, LocalDate.of(2008, Month.MAY, 1), bob);
    static Book b12 = new Book(9, LocalDate.of(1978, Month.FEBRUARY, 1), dennis);
    static Book b13 = new Book(10, LocalDate.of(1995, Month.FEBRUARY, 1), mike);
    static Book b14 = new Book(10, LocalDate.of(1995, Month.FEBRUARY, 1),null);

    public static List<Book> givenBooksWithNulls(){
        return Arrays.asList(b1, b2, b3, b4, null, b5, b6, b7, b8, null, b13, b9, b10, b14, b11, b12);
    }

    public static void main(String[] args) {
        List<Book> books = givenBooksWithNulls();
        Function<Book, Integer> fPrice = b -> b == null ? null : b.getPrice();
        Function<Book, String> fAuthor = b -> b == null ? null : b.getAuthor() == null ? null : b.getAuthor().getName();
        // Woks good with the Functions as Variables
        books.stream()
                .filter(b -> b == null || b.getDate().getYear() > 1990)
                .sorted(comparing(fPrice, nullsLast(naturalOrder()))
                        .thenComparing(fAuthor, nullsLast(reverseOrder()))
                )
                .forEach(System.out::println);

        // It doesn't work when I put the content of the Functions inline
        // Java says getPrice() cannot be find in java.lang.Object
        // it seems like comparing doesn't like the Lambda expression
//        books.stream()
//                .filter(b -> b == null || b.getDate().getYear() > 1990)
//                .sorted(comparing(b -> b == null ? null : b.getPrice(), nullsLast(naturalOrder()))
//                        .thenComparing(b -> b == null ? null : b.getAuthor() == null ? null : b.getAuthor().getName(), nullsLast(reverseOrder()))
//                )
//                .forEach(System.out::println);


        System.out.println("====================================");

        // Other example using Optional

        Predicate<Book> fFilter = b -> Optional.ofNullable(b)
                .map(bb -> bb.getDate().getYear() > 1990)
                .orElse(false);

        Function<Book, Integer> fPrice2 = b -> Optional.ofNullable(b)
                .map(Book::getPrice)
                .orElse(null);

        Function<Book, String> fAuthor2 = b -> Optional.ofNullable(b)
                .map(Book::getAuthor)
                .map(Author::getName)
                .orElse(null);

        // This also works when I use the Predicate and Functions as variables
        givenBooksWithNulls().stream()
                .filter(fFilter)
                .sorted(comparing(fPrice2, nullsLast(naturalOrder()))
                        .thenComparing(fAuthor2, nullsLast(reverseOrder()))
                )
                .forEach(System.out::println);

        // Same thing Here, not working when we replace the variables by their content of Lambda expression
//        givenBooksWithNulls().stream()
//                .filter(b -> Optional.ofNullable(b)
//                        .map(bb -> bb.getDate().getYear() > 1990)
//                        .orElse(false))
//                .sorted(comparing(b -> Optional.ofNullable(b)
//                        .map(Book::getPrice)
//                        .orElse(null), nullsLast(naturalOrder()))
//                        .thenComparing(b -> Optional.ofNullable(b)
//                                .map(Book::getAuthor)
//                                .map(Author::getName)
//                                .orElse(null), nullsLast(reverseOrder()))
//                )
//                .forEach(System.out::println);
    }
}

更新:

我正在为希望将其分开的那些人分隔此更新中的代码。

Author.java

package com.slide;

public class Author {
    private String name;

    public Author(String name) {
        this.name = name;
    }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

Book.java

package com.slide;

import java.time.LocalDate;

public class Book {
    private int price;
    private LocalDate date;
    private Author author;

    public Book(int price, LocalDate date, Author author) {
        this.price = price;
        this.date = date;
        this.author = author;
    }

    public int getPrice() { return price; }
    public void setPrice(int price) { this.price = price; }
    public LocalDate getDate() { return date; }
    public void setDate(LocalDate date) { this.date = date; }
    public Author getAuthor() { return author; }
    public void setAuthor(Author author) { this.author = author; }

    @Override
    public String toString() {
        String authorName = author != null && author.getName() != null ? author.getName() : "null";
        return "{ price : "
                .concat(String.valueOf(price))
                .concat(", year : ")
                .concat(date != null ? date.toString() : "null")
                .concat(", author : ")
                .concat(authorName)
                .concat("}");
    }
}

DataExample.java

package com.slide;

import java.time.LocalDate;
import java.time.Month;
import java.util.Arrays;
import java.util.List;

public class DataExample {
    static Author john = new Author("John");
    static Author marguerite = new Author("Marguerite");
    static Author charlton = new Author("Charlton");
    static Author gwen = new Author("Gwen");
    static Author marion = new Author("Marion");
    static Author mark = new Author("Mark");
    static Author jerry = new Author("Jerry");
    static Author bob = new Author("Bob");
    static Author dennis = new Author("Dennis");
    static Author mike = new Author(null);


    static Book b1 = new Book(15, LocalDate.of(1983, Month.JANUARY, 1), john);
    static Book b2 = new Book(8, LocalDate.of(1998, Month.AUGUST, 1), marguerite);
    static Book b3 = new Book(14, LocalDate.of(1992, Month.SEPTEMBER, 1), john);
    static Book b4 = new Book(10, LocalDate.of(2016, Month.MAY, 1), charlton);
    static Book b5 = new Book(10, LocalDate.of(1997, Month.FEBRUARY, 1), gwen);
    static Book b6 = new Book(8, LocalDate.of(1986, Month.AUGUST, 1), charlton);
    static Book b7 = new Book(54, LocalDate.of(1998, Month.MARCH, 1), john);
    static Book b8 = new Book(10, LocalDate.of(1997, Month.FEBRUARY, 1), marion);
    static Book b9 = new Book(32, LocalDate.of(2013, Month.JULY, 1), mark);
    static Book b10 = new Book(5, LocalDate.of(1997, Month.AUGUST, 1), jerry);
    static Book b11 = new Book(10, LocalDate.of(2008, Month.MAY, 1), bob);
    static Book b12 = new Book(9, LocalDate.of(1978, Month.FEBRUARY, 1), dennis);
    static Book b13 = new Book(10, LocalDate.of(1995, Month.FEBRUARY, 1), mike);
    static Book b14 = new Book(10, LocalDate.of(1995, Month.FEBRUARY, 1),null);

    public static List<Book> givenBooksWithNulls(){
        return Arrays.asList(b1, b2, b3, b4, null, b5, b6, b7, b8, null, b13, b9, b10, b14, b11, b12);
    }
}

Main.java

package com.slide;

import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;

import static java.util.Comparator.*;
import static java.util.Comparator.reverseOrder;

public class Main {

    public static void main(String[] args) {
        List<Book> books = DataExample.givenBooksWithNulls();
        exampleOne(books);
        System.out.println("====================================");
        exampleTwo(books);

    }

    private static void exampleOne(List<Book> books) {
        Function<Book, Integer> fPrice = b -> b == null ? null : b.getPrice();
        Function<Book, String> fAuthor = b -> b == null ? null : b.getAuthor() == null ? null : b.getAuthor().getName();
        // Woks good with the Functions as Variables
        books.stream()
                .filter(b -> b == null || b.getDate().getYear() > 1990)
                .sorted(comparing(fPrice, nullsLast(naturalOrder()))
                        .thenComparing(fAuthor, nullsLast(reverseOrder()))
                )
                .forEach(System.out::println);

        // It doesn't work when I put the content of the Functions inline
        // Java says getPrice() cannot be find in java.lang.Object
        // it seems like comparing doesn't like the Lambda expression
//        books.stream()
//                .filter(b -> b == null || b.getDate().getYear() > 1990)
//                .sorted(comparing(b -> b == null ? null : b.getPrice(), nullsLast(naturalOrder()))
//                        .thenComparing(b -> b == null ? null : b.getAuthor() == null ? null : b.getAuthor().getName(), nullsLast(reverseOrder()))
//                )
//                .forEach(System.out::println);
    }

    private static void exampleTwo(List<Book> books) {
        // Other example using Optional

        Predicate<Book> fFilter = b -> Optional.ofNullable(b)
                .map(bb -> bb.getDate().getYear() > 1990)
                .orElse(false);

        Function<Book, Integer> fPrice2 = b -> Optional.ofNullable(b)
                .map(Book::getPrice)
                .orElse(null);

        Function<Book, String> fAuthor2 = b -> Optional.ofNullable(b)
                .map(Book::getAuthor)
                .map(Author::getName)
                .orElse(null);

        // This also works when I use the Predicate and Functions as variables
        books.stream()
                .filter(fFilter)
                .sorted(comparing(fPrice2, nullsLast(naturalOrder()))
                        .thenComparing(fAuthor2, nullsLast(reverseOrder()))
                )
                .forEach(System.out::println);

        // Same thing Here, not working when we replace the variables by their content of Lambda expression
//        books.stream()
//                .filter(b -> Optional.ofNullable(b)
//                        .map(bb -> bb.getDate().getYear() > 1990)
//                        .orElse(false))
//                .sorted(comparing(b -> Optional.ofNullable(b)
//                        .map(Book::getPrice)
//                        .orElse(null), nullsLast(naturalOrder()))
//                        .thenComparing(b -> Optional.ofNullable(b)
//                                .map(Book::getAuthor)
//                                .map(Author::getName)
//                                .orElse(null), nullsLast(reverseOrder()))
//                )
//                .forEach(System.out::println);
    }
}

3 个答案:

答案 0 :(得分:1)

将变量键入为Function<Book, Integer>时,编译器将知道确切的泛型类型。内联版本中缺少此信息。指定显式类型参数有助于如下:

                .sorted(
                    Comparator.<Book, Integer> comparing(....

另请参阅this答案。

答案 1 :(得分:1)

问题在于泛型类型的解析。我不确定,但是我认为这是thenComparing的签名,期望Function<? super T, ...>。这意味着“根”比较器必须绑定到sth。 “超级” T,即尽可能广泛的类型,即Object

明确定义泛型类型,也将使其编译(请参见Michal的anwser):

.sorted(Comparator.<Book, Integer> comparing(b -> b.getPrice())
   .thenComparing(...))

答案 2 :(得分:0)

IntellIj告诉bObject,而不是Book

IntellIj error

要使其正常运行,请将b强制转换为Book

books.stream()
        .filter(b -> b == null || b.getDate().getYear() > 1990)
        .sorted(comparing((Book b) -> b == null ? null : b.getPrice(), nullsLast(naturalOrder()))
                .thenComparing(b -> b == null ? null : b.getAuthor() == null ? null : b.getAuthor().getName(), nullsLast(reverseOrder()))
        )
        .forEach(System.out::println);

第二部分相同。