I am studying lambda expressions and I am struggling with on how to use the java.util.function.Function to sort a collection. Could someone help me or at give me some pointers on how to achieve this?
I have a book POJO and a class that stores books in a collection. I am trying to use a lambda expression of the Function interface to return the same collection but sorted. I could use Collections.sort() and return it that way but I was thinking there was a way to do it with the Function interface.
public class BookTable {
private Map<Integer, Book> bookMap;
public BookTable() {
this.bookMap = new HashMap<>();
}
public void addBook(Book book) {
bookMap.put(size(), book);
}
public int size() {
return bookMap.size();
}
public List<Book> getRecord(int key) {
return Collections.singletonList(bookMap.get(key));
}
public List<Book> getRecordsWhere(Predicate<Book> predicate) {
return bookMap.values()
.stream()
.filter(predicate)
.collect(Collectors.toList());
}
public List<Book> getSortedRecords(Function<Book, Comparable> fieldExtractor) {
// Return sorted list....
}
}
Book POJO
public class Book {
private String title;
private String author;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
Just a quick test...
public class BookTableTest {
public static void main(String[] args) {
File file = new File("booklist.csv");
BookTable table = new BookTable();
Book book1 = new Book();
book1.setAuthor("Author 1");
book1.setTitle("Title 1");
Book book2 = new Book();
book2.setAuthor("Book 2 Author 1");
book2.setTitle("Book 2 Title 1");
Book book3 = new Book();
book3.setAuthor("The best author");
book3.setTitle("The best title");
table.addBook(book3);
table.addBook(book1);
table.addBook(book2);
System.out.println("## Sorted by Title");
System.out.println(table.printRecords(table.getSortedRecords(Book::getTitle)));
System.out.println();
System.out.println("## Sorted by Author");
System.out.println(table.printRecords(table.getSortedRecords(Book::getAuthor)));
}
}
The Lambda expression is used to provide the implementation of an interface which has functional interface. It saves a lot of code. In case of lambda expression, we don't need to define the method again for providing the implementation. Here, we just write the implementation code.
Any interface with a SAM(Single Abstract Method) is a functional interface, and its implementation may be treated as lambda expressions.
No, all the lambda expressions in this code implement the BiFunction<Integer, Integer, Integer> function interface. The body of the lambda expressions is allowed to call methods of the MathOperation class. It doesn't have to refer only to methods of a functional interface.
A lambda expression (lambda) is a short-form replacement for an anonymous class. Lambdas simplify the use of interfaces that declare single abstract methods. Such interfaces are known as functional interfaces. A functional interface can define as many default and static methods as it requires.
Part of the value of streams is not having to reinvent all of the sorting, filtering, and collection methods. Instead of having filter method, a sort method, a print method, etc., I would simply have one method that returns a Collection<Book>
. Let the caller do whatever they want with that collection.
public Collection<Book> getRecords() {
return bookMap.values();
}
...
table.getRecords().stream()
.filter(book -> book.getAuthor().equals("Charles Dickens"))
.sorted(Comparator.comparing(Book::getTitle))
.forEach(System.out::println);
The advantage of this approach is that it allows the user to chain together the different operations however they like. They can filter and sort and print if that's what they want to do.
Here is an implementation
List<Book> getSortedRecords(Predicate<Book> predicate, Comparator<Book> comparator) {
return this.bookMap.values().stream().filter(predicate).sorted(comparator).collect(Collectors.toList());
}
where the Predicate
and Comparator
can be passed as a arguments for getSortedRecords
like below
getSortedRecords(b -> b != null, Comparator.comparing(Book::getTitle))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With