2016-09-01 3 views
8

Я изучаю лямбда-выражения, и я борюсь с тем, как использовать функцию java.util.function.Function для сортировки коллекции. Может ли кто-нибудь помочь мне или дать мне несколько указаний о том, как достичь этого?Функциональный интерфейс как лямбда для сортировки коллекции?

У меня есть книга POJO и класс, в котором хранятся книги в коллекции. Я пытаюсь использовать лямбда-выражение интерфейса Function для возврата той же коллекции, но отсортировано. Я мог бы использовать Collections.sort() и вернуть его таким образом, но я думал, что есть способ сделать это с помощью интерфейса Function.

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.... 
    } 
} 

Книга 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; 
    } 
} 

Просто быстрый тест ...

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))); 

    } 
} 

ответ

6

Часть значения потоков не требует повторного использования всех методов сортировки, фильтрации и сбора. Вместо метода фильтрации, метода сортировки, метода печати и т. Д., У меня просто был бы один метод, который возвращает Collection<Book>. Пусть вызывающий абонент делает все, что захочет, с этой коллекцией.

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); 

Преимущество этого подхода заключается в том, что он позволяет пользователю объединять различные операции, но им нравится. Они могут фильтровать и сортировать и распечатать, если это то, что они хотят сделать.

+0

Я думаю, что это был отличный ответ Джон, но мне было любопытно, как это сделать с помощью интерфейса Function. Я не был уверен, что после часа или около того исследований. Я не думал, что могу просто использовать лямбду для интерфейса Comparator с сортировкой. Следующий комментарий - это пример использования интерфейса Function, который я могу четко видеть, почему вы просто вернете список и позволяете пользователю делать то, что им нужно. – Grim

+0

bookMap .values ​​() .stream() .sorted ((Книга Книга1, Книга book2) -> fieldExtractor.apply (Книга1) .compareTo (fieldExtractor.apply (book2))) .сбор (Collectors.toList()); – Grim

1

Вот реализация

List<Book> getSortedRecords(Predicate<Book> predicate, Comparator<Book> comparator) { 
    return this.bookMap.values().stream().filter(predicate).sorted(comparator).collect(Collectors.toList()); 
} 

где Predicate и Comparator могут быть переданы в качестве аргументов для getSortedRecords, как показано ниже

getSortedRecords(b -> b != null, Comparator.comparing(Book::getTitle)) 
0

Я хотел решение, используя интерфейс функции, но ответ марки Джона Kugelman в действительно хорошая точка ... Это решение, которое я получил после нескольких часов исследований.

Сопоставимый общий тип, поэтому я должен был параметризовать его, но параметрирование его не сработало.

То, что я пытаюсь сделать:

public List<Book> getSortedRecords(Function<Book, Comparable> fieldExtractor) { 

    return bookMap 
      .values() 
      .stream() 
      .sorted(Comparator.comparing(fieldExtractor)) 
      .collect(Collectors.toList()); 
} 

Метод не знал тип поля, который собирался извлечь из этой книги. Решение заключалось в том, чтобы сделать этот метод сам по себе общим:

public <T extends Comparable<? super T>> List<Book> getSortedRecords(Function<Book, T> fieldExtractor) { 

    return bookMap 
      .values() 
      .stream() 
      .sorted(Comparator.comparing(fieldExtractor)) 
      .collect(Collectors.toList()); 
}