Reputation: 2097
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)));
}
}
Upvotes: 9
Views: 4264
Reputation: 2097
I wanted a solution using the Function interface but John Kugelman's answer makes a really good point....This is the solution I ended up using after a few hours of research.
Comparable is a generic type, so I should have parameterized it but parameterizing it didn't work.
What I was trying to do:
public List<Book> getSortedRecords(Function<Book, Comparable> fieldExtractor) {
return bookMap
.values()
.stream()
.sorted(Comparator.comparing(fieldExtractor))
.collect(Collectors.toList());
}
The method didn't know the type of the field that was going to be extracted from the book. The solution was to make the method itself generic:
public <T extends Comparable<? super T>> List<Book> getSortedRecords(Function<Book, T> fieldExtractor) {
return bookMap
.values()
.stream()
.sorted(Comparator.comparing(fieldExtractor))
.collect(Collectors.toList());
}
Upvotes: 0
Reputation: 12817
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))
Upvotes: 1
Reputation: 361879
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.
Upvotes: 8
Reputation: 616
You can use the method sorted of stream. https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#sorted--
Upvotes: 0