I have got two cases of method referance:
Case 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 Book
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());
}
}
Both method referances work fine in this case (BookLoanRecord::createLoanRecordStaticVersion, Book::createLoanRecordNotStaticVersion).
Case 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()));
}
}
}
Adding lacking 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
}
and
public enum Sex {
MALE,
FEMALE;
public static Sex getRandomSex(){
Random random = new Random();
return values()[random.nextInt(values().length)];
}
}
And here I'm getting this error: Person is not a functional interface in method generateRandomPerson()
The question is why ? I don't understand why case 1 is ok and I'm getting an error in case 2. Why it wants class Person to be functional interface? What needs to be change to use method referance in case 2 as well ?