Java 方法引用抱怨 class 不是功能接口
Java method referance complains about class not being functional interface
我有两个方法参考案例:
案例 1:
public class Main {
static List<Person> personList = List.of(
new Person("Daria", 27, List.of(new Book("Potop", "H. Sienkiewicz"),
new Book("Dywizjon 303", "A. Fiedler"))),
new Person("Ola", 34, List.of(new Book("Czysty kod", "R.C. Martin"),
new Book("Hobbit", "J. R. R. Tolkien"))),
new Person("Ala", 53, List.of(new Book("Potop", "H. Sienkiewicz"),
new Book("Wladca pierscieni", "J. R. R. Tolkien"))),
new Person("Julka", 12, List.of(new Book("Dywizjon 303", "A. Fiedler"),
new Book("Hobbit", "J. R. R. Tolkien"))),
new Person("Zuzia", 7, List.of(new Book("Robinson Crusoe", "D. Defoe"),
new Book("Alicja w krainie czarow", "L. Carroll")))
);
public static void main(String[] args) {
streamWithFunction_map();
}
public static void streamWithFunction_map(){
// map() - let you convert object to sth else
// List<String> to uppercase
List<String> namesInCapitalList = personList.stream().map(person -> person.getName().toUpperCase()).collect(Collectors.toList());
namesInCapitalList.forEach(System.out::println); //DARIA OLA ALA JULKA ZUZIA
// list of objects to list of Integers
List<Integer> ageList = personList.stream().map(Person::getAge).collect(Collectors.toList());
ageList.forEach(System.out::println); // 27 34 53 12 7
// list of object A to list of object b
List<BookLoanRecord> bookLoanRecordList_way1 = personList.stream()
.map(person -> person.getBooks().stream().map(BookLoanRecord::createLoanRecordStaticVersion).collect(Collectors.toList()))
.flatMap(Collection::stream)
.collect(Collectors.toList());
List<BookLoanRecord> bookLoanRecordList_way2 = personList.stream()
.map(person -> person.getBooks().stream().map(Book::createLoanRecordNotStaticVersion).collect(Collectors.toList()))
.flatMap(Collection::stream)
.collect(Collectors.toList());
List<BookLoanRecord> bookLoanRecordList_way3 = personList.stream()
.map(Person::getBooks)
.flatMap(Collection::stream)
.map(Book::createLoanRecordNotStaticVersion)
.collect(Collectors.toList());
}
}
Class 书
public class Book {
String title;
String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
//getters & setters
// The same method as createLoanRecordStaticVersion but without static
public BookLoanRecord createLoanRecordNotStaticVersion(){
return new BookLoanRecord(this.title, this.author, LocalDateTime.now());
}
}
Class BookLoanRecord
public class BookLoanRecord {
String title;
String author;
LocalDateTime dateTime;
public BookLoanRecord(String title, String author, LocalDateTime dateTime) {
this.title = title;
this.author = author;
this.dateTime = dateTime;
}
//getters & setters
//Needs to be static if we want to use it as method reference in stream
public static BookLoanRecord createLoanRecordStaticVersion(Book book){
return new BookLoanRecord(book.title, book.author, LocalDateTime.now());
}
}
在这种情况下,两种方法引用都可以正常工作(BookLoanRecord::createLoanRecordStaticVersion,Book::createLoanRecordNotStaticVersion)。
案例 2:
public class Main {
public static void main(String[] args) {
// returnTime();
generateRandomPerson();
}
public static Person generateRandomPerson() {
// return PersonGenerator.generateRandomPerson(); //all good here
return PersonGenerator::generateRandomPerson; //error:
}
}
PersonGenerato class:
public class PersonGenerator {
private static final Random random = new Random();
private static final List<String> femaleNamesList = List.of("Diana", "Daria", "Ola", "Ala", "Julka", "Monika", "Magda");
private static final List<String> maleNamesList = List.of("Adam", "Tomek", "Arek", "Olek", "Alek", "Julek");
private static final List<String> surnameList = List.of("Newton", "Smith", "Nowak", "Kowalczyk", "Robinson");
public static Person generateRandomPerson(){
Sex sex = Sex.getRandomSex();
String surname= generateRandomSurname();
String name = generateRandomName(sex);
return new Person(name, surname, sex);
}
private static String generateRandomSurname(){
return surnameList.get(random.nextInt(surnameList.size()));
}
private static String generateRandomName(Sex sex){
if (sex == Sex.MALE){
return maleNamesList.get(random.nextInt(maleNamesList.size()));
} else {
return femaleNamesList.get(random.nextInt(femaleNamesList.size()));
}
}
}
补充不足classes:
public class Person {
private String name;
private String surname;
private Sex sex;
public Person(String name, String surname, Sex sex) {
this.name = name;
this.surname = surname;
this.sex = sex;
}
public Person() {
}
// setters and getters
}
和
public enum Sex {
MALE,
FEMALE;
public static Sex getRandomSex(){
Random random = new Random();
return values()[random.nextInt(values().length)];
}
}
我在这里遇到了这个错误:
Person 不是函数式接口
在方法 generateRandomPerson()
问题是为什么?我不明白为什么情况 1 没问题,而我在情况 2 中遇到错误。
为什么它希望 class Person 成为功能接口?
在案例 2 中也需要更改什么才能使用方法参考?
因为方法引用是对函数的引用。您的方法需要 Person
类型作为 return 类型,而您正在尝试 return 类型 Supplier
。您需要将 return 类型从 Person
更改为 Supplier<Person>
如果比较方法签名,您会发现差异。
流图(函数 mapper)
这里的方法需要一个Function
(表示接受一个参数并产生结果的函数)
public static Person generateRandomPerson()
此处预期的 return 值是 Person
,而不是生成 Person
.
的方法
我有两个方法参考案例:
案例 1:
public class Main {
static List<Person> personList = List.of(
new Person("Daria", 27, List.of(new Book("Potop", "H. Sienkiewicz"),
new Book("Dywizjon 303", "A. Fiedler"))),
new Person("Ola", 34, List.of(new Book("Czysty kod", "R.C. Martin"),
new Book("Hobbit", "J. R. R. Tolkien"))),
new Person("Ala", 53, List.of(new Book("Potop", "H. Sienkiewicz"),
new Book("Wladca pierscieni", "J. R. R. Tolkien"))),
new Person("Julka", 12, List.of(new Book("Dywizjon 303", "A. Fiedler"),
new Book("Hobbit", "J. R. R. Tolkien"))),
new Person("Zuzia", 7, List.of(new Book("Robinson Crusoe", "D. Defoe"),
new Book("Alicja w krainie czarow", "L. Carroll")))
);
public static void main(String[] args) {
streamWithFunction_map();
}
public static void streamWithFunction_map(){
// map() - let you convert object to sth else
// List<String> to uppercase
List<String> namesInCapitalList = personList.stream().map(person -> person.getName().toUpperCase()).collect(Collectors.toList());
namesInCapitalList.forEach(System.out::println); //DARIA OLA ALA JULKA ZUZIA
// list of objects to list of Integers
List<Integer> ageList = personList.stream().map(Person::getAge).collect(Collectors.toList());
ageList.forEach(System.out::println); // 27 34 53 12 7
// list of object A to list of object b
List<BookLoanRecord> bookLoanRecordList_way1 = personList.stream()
.map(person -> person.getBooks().stream().map(BookLoanRecord::createLoanRecordStaticVersion).collect(Collectors.toList()))
.flatMap(Collection::stream)
.collect(Collectors.toList());
List<BookLoanRecord> bookLoanRecordList_way2 = personList.stream()
.map(person -> person.getBooks().stream().map(Book::createLoanRecordNotStaticVersion).collect(Collectors.toList()))
.flatMap(Collection::stream)
.collect(Collectors.toList());
List<BookLoanRecord> bookLoanRecordList_way3 = personList.stream()
.map(Person::getBooks)
.flatMap(Collection::stream)
.map(Book::createLoanRecordNotStaticVersion)
.collect(Collectors.toList());
}
}
Class 书
public class Book {
String title;
String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
//getters & setters
// The same method as createLoanRecordStaticVersion but without static
public BookLoanRecord createLoanRecordNotStaticVersion(){
return new BookLoanRecord(this.title, this.author, LocalDateTime.now());
}
}
Class BookLoanRecord
public class BookLoanRecord {
String title;
String author;
LocalDateTime dateTime;
public BookLoanRecord(String title, String author, LocalDateTime dateTime) {
this.title = title;
this.author = author;
this.dateTime = dateTime;
}
//getters & setters
//Needs to be static if we want to use it as method reference in stream
public static BookLoanRecord createLoanRecordStaticVersion(Book book){
return new BookLoanRecord(book.title, book.author, LocalDateTime.now());
}
}
在这种情况下,两种方法引用都可以正常工作(BookLoanRecord::createLoanRecordStaticVersion,Book::createLoanRecordNotStaticVersion)。
案例 2:
public class Main {
public static void main(String[] args) {
// returnTime();
generateRandomPerson();
}
public static Person generateRandomPerson() {
// return PersonGenerator.generateRandomPerson(); //all good here
return PersonGenerator::generateRandomPerson; //error:
}
}
PersonGenerato class:
public class PersonGenerator {
private static final Random random = new Random();
private static final List<String> femaleNamesList = List.of("Diana", "Daria", "Ola", "Ala", "Julka", "Monika", "Magda");
private static final List<String> maleNamesList = List.of("Adam", "Tomek", "Arek", "Olek", "Alek", "Julek");
private static final List<String> surnameList = List.of("Newton", "Smith", "Nowak", "Kowalczyk", "Robinson");
public static Person generateRandomPerson(){
Sex sex = Sex.getRandomSex();
String surname= generateRandomSurname();
String name = generateRandomName(sex);
return new Person(name, surname, sex);
}
private static String generateRandomSurname(){
return surnameList.get(random.nextInt(surnameList.size()));
}
private static String generateRandomName(Sex sex){
if (sex == Sex.MALE){
return maleNamesList.get(random.nextInt(maleNamesList.size()));
} else {
return femaleNamesList.get(random.nextInt(femaleNamesList.size()));
}
}
}
补充不足classes:
public class Person {
private String name;
private String surname;
private Sex sex;
public Person(String name, String surname, Sex sex) {
this.name = name;
this.surname = surname;
this.sex = sex;
}
public Person() {
}
// setters and getters
}
和
public enum Sex {
MALE,
FEMALE;
public static Sex getRandomSex(){
Random random = new Random();
return values()[random.nextInt(values().length)];
}
}
我在这里遇到了这个错误: Person 不是函数式接口 在方法 generateRandomPerson()
问题是为什么?我不明白为什么情况 1 没问题,而我在情况 2 中遇到错误。 为什么它希望 class Person 成为功能接口? 在案例 2 中也需要更改什么才能使用方法参考?
因为方法引用是对函数的引用。您的方法需要 Person
类型作为 return 类型,而您正在尝试 return 类型 Supplier
。您需要将 return 类型从 Person
更改为 Supplier<Person>
如果比较方法签名,您会发现差异。
流图(函数 mapper)
这里的方法需要一个Function
(表示接受一个参数并产生结果的函数)
public static Person generateRandomPerson()
此处预期的 return 值是 Person
,而不是生成 Person
.