有没有解释为什么Java8Lambda表达式使用函数变量而不内联工作
有人能解释为什么我把lambda表达式放进直升机里吗。在下面的代码中,compring()不起作用。当我将相同的表达式提取到函数变量中时,它工作得很好
有两个示例(在Main.java类中),其中一个没有编译(可选),另一个正在编译,但在执行时抛出错误。我在注释中加入了不起作用的代码,以表明当表达式被提取到变量中时,它可以正常工作
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);
}
}
更新:
我在这个更新中为那些喜欢分离代码的人分离代码
作者。爪哇
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; }
}
书。爪哇
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("}");
}
}
数据示例。爪哇
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);
}
}
梅因。爪哇
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);
}
}
# 1 楼答案
问题是泛型类型的解决方案。我不确定,但我认为这是
thenComparing
的签名,期待着Function<? super T, ...>
。这意味着,“根”比较器绑定到某个“超级”T
,即绑定到尽可能广泛的类型,即Object
显式定义泛型类型也会使其可编译(参见Michal的anwser):
# 2 楼答案
将变量类型化为
Function<Book, Integer>
时,编译器知道确切的泛型类型。内联版本中缺少此信息。指定显式类型参数会有帮助,如下所示:另见this答案
# 3 楼答案
IntellIj告诉
b
是Object
,而不是Book
:为了让它工作,将
b
转换为Book
:第二部分也是如此