2014-09-15 3 views
0

У меня очень простой Java-компонент, WatchedFile, который имеет поле fileName.Functionaljava: сортировка списка произвольных типов

Я хотел бы отсортировать fj.data.List из WatchedFile объектов, но я борюсь с определяя fj.Ord для sort() метода списка. Это то, что я придумал:

protected List<WatchedFile> getWatchedFileList(String path) throws IOException { 
    List<File> files = List.list(new File(path).listFiles()); 
    return files 
      .map((file) -> new WatchedFile(file.getName(), false, file.length())) 
      .sort(Ord.ord(new F<WatchedFile, F<WatchedFile, Ordering>>() 
      { 
       @Override 
       public F<WatchedFile, Ordering> f(final WatchedFile watchedFile1) 
       { 
        return new F<WatchedFile, Ordering>() 
        { 
         @Override 
         public Ordering f(final WatchedFile watchedFile2) 
         { 
          int compareResult = watchedFile1.fileName.compareTo(watchedFile2.fileName); 
          return (compareResult < 0 ? Ordering.LT : 
            (compareResult > 0 ? Ordering.GT : Ordering.EQ)); 
         } 
        }; 
       } 
      })); 
} 

Это некрасиво! Я уверен, что есть лучший способ создания объекта Ord ... Возможно, используется какая-то магия Java 8?

ответ

2
protected List<WatchedFile> getWatchedFileList(String path) throws IOException { 
    List<File> files = Arrays.asList(new File(path).listFiles()); 
    return files.stream() 
     .map(file -> new WatchedFile(file.getName(), false, file.length())) 
     .sorted((wf1, wf2)->wf1.fileName.compareTo(wf2.fileName)) 
     .collect(Collectors.toList()); 
} 

Рекомендуется иметь метод public String getFileName() в классе WatchedFile. В этом случае вы можете просто сказать:

protected List<WatchedFile> getWatchedFileList(String path) throws IOException { 
    List<File> files = Arrays.asList(new File(path).listFiles()); 
    return files.stream() 
     .map(file -> new WatchedFile(file.getName(), false, file.length())) 
     .sorted(Comparator.comparing(WatchedFile::getFileName)) 
     .collect(Collectors.toList()); 
} 

И, используя NiO2 для получения записей каталога, это может выглядеть следующим образом:

protected List<WatchedFile> getWatchedFileList(String path) throws IOException { 
    try { 
     return Files.list(Paths.get(path)) 
      .map(p -> new WatchedFile(p.toString(), false, fileSize(p))) 
      .sorted(Comparator.comparing(WatchedFile::getFileName)) 
      .collect(Collectors.toList()); 
    } catch(UncheckedIOException ex) { throw ex.getCause(); } 
} 
private long fileSize(Path path) { 
    try { return Files.size(path); } 
    catch (IOException ex) { throw new UncheckedIOException(ex); } 
} 

Если вы хотите остаться в «Функционально Java»API, решение может выглядеть следующим образом:

protected List<WatchedFile> getWatchedFileList(String path) throws IOException { 
    List<File> files = List.list(new File(path).listFiles()); 
    return files 
     .map(file -> new WatchedFile(file.getName(), false, file.length())) 
     .sort(Ord.stringOrd.comap(wf -> wf.fileName)); 
} 

ключевым моментом является то, что вам не нужно (не нужно) повторно реализовать способ, String с. Вместо этого задайте функцию, чтобы получить значение свойства для сравнения. Сравнение с методом фабрики Java 8 Comparator.comparing используется во втором примере кода.

+0

Вы можете сделать эквивалент кода вопроса «используя некоторую магию Java 8»: '.sort (Ord.ord (a-> b-> Ord.stringOrd.compare (a.fileName, b.fileName))) ', но он по-прежнему уродлив по сравнению с альтернативами ... – Holger

+0

Это здорово, Ord.stringOrd.comap() был именно тем, что я искал. Я также попытаюсь переоценить потребность в функциональных функциях с учетом особенностей Java 8. Большое спасибо. – egbokul