Получение списка подкаталогов с помощью FlatMap
Ранее мы видели, как составить список файлов в указанном каталоге. Давайте посмотрим, как перемещаться по прямым подкаталогам указанного каталога (глубина равна 1), сначала реализуем простую версию, а затем используем для ее реализации более удобный метод FlatMap().
Сначала мы используем традиционный цикл for для перемещения по указанному каталогу. Если в подкаталоге есть файлы, добавьте их в список, в противном случае добавьте в список подкаталог; Наконец, распечатайте общее количество всех файлов. Код ниже — это для жесткого режима.
Скопируйте код кода следующим образом:
public static void listTheHardWay() {
List<File> files = new ArrayList<>();
File[] filesInCurrentDir = новый файл(".").listFiles();
for (Файл-файл: filesInCurrentDir) {
Файл[] filesInSubDir = file.listFiles();
если (filesInSubDir! = ноль) {
files.addAll(Arrays.asList(filesInSubDir));
} еще {
файлы.добавить(файл);
}
}
System.out.println("Count: " + files.size())
}
Сначала мы получаем список файлов в текущем каталоге, а затем просматриваем его. Для каждого файла, если у него есть подфайлы, добавьте их в список. С этим нет проблем, но есть некоторые общие проблемы: изменчивость, паранойя базового типа, императивность, многословие кода и т. д. Небольшой метод FlatMap() может решить эти проблемы.
Как следует из названия, этот метод выравнивается после сопоставления. Он отображает элементы коллекции точно так же, как и функция map(). Но в отличие от метода Map(), лямбда-выражение в методе Map() возвращает только элемент, а здесь возвращается объект Stream. Таким образом, этот метод сглаживает несколько потоков и отображает каждый элемент внутри сглаженного потока.
Мы можем использовать FlatMap() для выполнения различных операций, но рассматриваемая задача иллюстрирует ее ценность. В каждом подкаталоге есть список или поток файлов, и мы хотим получить список файлов во всех подкаталогах текущего каталога.
Некоторые каталоги могут быть пустыми или не иметь дочерних элементов. В этом случае мы оборачиваем пустой каталог или файл в объект потока. Если мы хотим игнорировать файл, метод FlatMap() в JDK также может очень хорошо обрабатывать пустые файлы; он объединит нулевую ссылку в поток как пустую коллекцию. Давайте посмотрим на использование метода FlatMap().
Скопируйте код кода следующим образом:
public static void BetterWay() {
Список файлов <File> =
Stream.of(новый файл(".").listFiles())
.flatMap(file -> file.listFiles() == null ?
Stream.of(файл): Stream.of(file.listFiles()))
.collect(toList());
System.out.println("Count: " + files.size());
}
Сначала мы получаем поток подфайлов текущего каталога, а затем вызываем его метод FlatMap(). Затем передайте этому методу лямбда-выражение, которое вернет поток подфайлов указанного файла. Метод FlatMap() возвращает коллекцию файлов во всех подкаталогах текущего каталога. Мы используем метод Collect() и метод toList()( в Collectors, чтобы собрать их в список.
Лямбда-выражение, которое мы передаем в FlatMap(), возвращает подфайл файла. Если нет, возвращается поток файла. Метод FlatMap() элегантно отображает этот поток в коллекцию потоков, затем выравнивает коллекцию и, наконец, объединяет ее в один поток.
Метод FlatMap() сокращает объем работы по разработке — он объединяет две последовательные операции, часто называемые кортежами, в одну элегантную операцию.
Мы уже знаем, как использовать метод FlatMap() для вывода списка всех файлов в ближайшем подкаталоге. Проследим за операциями модификации файлов.
Отслеживать изменения файлов
Мы уже знаем, как находить файлы и каталоги, но если мы хотим получать подсказки при создании, изменении или удалении файлов, это тоже очень просто. Такой механизм очень полезен для мониторинга изменений в специальных файлах, таких как файлы конфигурации и системные ресурсы. Давайте рассмотрим этот инструмент, представленный в Java 7, WatchService, который можно использовать для мониторинга изменений файлов. Многие из функций, которые мы видим ниже, взяты из JDK 7, но самым большим улучшением здесь является удобство, обеспечиваемое внутренними итераторами.
Давайте сначала напишем пример мониторинга изменений файлов в текущем каталоге. Класс Path в JDK соответствует экземпляру файловой системы, которая является фабрикой служб-наблюдателей. Мы можем зарегистрировать события уведомлений для этого сервиса, вот так:
Скопируйте код кода следующим образом:
конечный путь path = Paths.get(".");
окончательный WatchService watchService =
путь.getFileSystem()
.newWatchService();
path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
System.out.println("Сообщить о любом файле, измененном в течение следующей минуты...");
Мы зарегистрировали WatchService для наблюдения за изменениями в текущем каталоге. Вы можете опросить этот WatchService, чтобы получить информацию об операциях изменения файлов в каталоге, и он вернет нам эти изменения через WatchKey. Получив ключ, мы можем просмотреть все его события, чтобы получить подробную информацию об обновлении файла. Поскольку одновременно могут быть изменены несколько файлов, операция опроса может возвращать несколько событий. Давайте посмотрим на код опроса и обхода.
Скопируйте код кода следующим образом:
окончательный WatchKey watchKey = watchService.poll(1, TimeUnit.MINUTES);
если (watchKey! = ноль) {
watchKey.pollEvents()
.транслировать()
.forEach(событие ->
System.out.println(event.context()));
}
Как вы можете видеть здесь, функции Java 7 и Java 8 появляются одновременно. Мы преобразуем коллекцию, возвращаемую функцией pollEvents(), в поток Java 8, а затем используем его внутренний итератор для распечатки подробной информации об обновлении для каждого файла.
Давайте запустим этот код, а затем изменим файл sample.txt в текущем каталоге, чтобы проверить, сможет ли программа обнаружить это обновление.
Скопируйте код кода следующим образом:
Сообщите о любом файле, измененном в течение следующей 1 минуты...
образец.txt
Когда мы изменим этот файл, программа сообщит, что файл был изменен. Мы можем использовать эту функцию для мониторинга обновлений различных файлов и последующего выполнения соответствующих задач. Конечно, мы также можем регистрировать только операции создания или удаления файлов.
Подвести итог
Благодаря лямбда-выражениям и ссылкам на методы общие задачи, такие как манипулирование строками и файлами, а также создание пользовательских компараторов, становятся проще и лаконичнее. Анонимные внутренние классы становятся элегантными, а изменчивость исчезает, как утренний туман после восхода солнца. Еще одним преимуществом программирования в этом новом стиле является то, что вы можете использовать новые возможности JDK для эффективного перемещения по большим каталогам.
Теперь вы знаете, как создать лямбда-выражение и передать его методу. В следующей главе мы покажем, как использовать функциональные интерфейсы и лямбда-выражения для разработки программного обеспечения.