В Data Geekery мы любим Java. И так как мы действительно входим в свободный API jOOQ и запросы DSL , мы абсолютно взволнованы тем, что Java 8 принесет в нашу экосистему. Мы пару раз писали о приятных вкусностях Java 8 , и теперь мы чувствуем, что пришло время начать новую серию блогов,…
Ява 8 Пятница
Каждую пятницу мы показываем вам пару замечательных новых функций Java 8 в виде учебника, в которых используются лямбда-выражения, методы расширения и другие замечательные вещи. Вы найдете исходный код на GitHub .
Java 8 Goodie: новые новые API ввода / вывода
В предыдущем посте из этой серии мы показали, как лямбда-выражения Java 8 улучшают существующий (хотя и устаревший) API ввода-вывода JDK 1.2, главным образом, помогая вам выражать экземпляры java.io.FileFilter как лямбда-выражения.
Многие читатели справедливо отмечают, что большая часть API java.io была заменена на Java 7 API java.nio , где «N» означает «Новый» (я знаю. Новый. Старый. Старый-2. Старый- 2-FIXME. Старый-2-TODO…). Но с Java 8 дела обстоят еще лучше. Мы называем его новыми новыми API ввода / вывода (NNIO), хотя члены сообщества jOOQ предложили назвать его «Enterprise IO»:
@ lukaseder @ brunoborges @ ponzao +1 для «Enterprise IO» (в этом случае, конечно, не сработает) — Франц ван Беттрэй (@FrVaBe) 15 января 2014 г.
Вернуться к более конструктивным блогам. Давайте Files.walk() (каламбур, см. Files.walk() ) вокруг улучшенных функций Java 8 NIO. Давайте сначала посмотрим на новые методы в java.nio.Files . Это действительно здорово, что мы наконец можем просто перечислить содержимое Path! В Java 8 мы будем использовать недавно представленный Files.list() , который возвращает ленивый поток файлов:
|
1
2
|
Files.list(new File(".").toPath()) .forEach(System.out::println); |
Вывод, который я получаю это:
|
1
2
3
4
5
6
7
8
9
|
.\.git.\.gitignore.\.idea.\java8-goodies.iml.\LICENSE.txt.\pom.xml.\README.txt.\src.\target |
Помните, что forEach() является «терминальным методом» , то есть методом, который потребляет поток. Вы не должны вызывать какие-либо дополнительные методы в таком потоке.
Мы также можем пропустить все скрытые файлы и перечислить только первые три «обычных» файла, например:
|
1
2
3
4
5
|
Files.list(new File(".").toPath()) .filter(p -> !p.getFileName() .toString().startsWith(".")) .limit(3) .forEach(System.out::println); |
Новый вывод, который я получаю, это:
|
1
2
3
|
.\java8-goodies.iml.\LICENSE.txt.\pom.xml |
Это уже довольно круто. Это может стать лучше? Да, оно может. Вы также можете «пройтись» по всей файловой иерархии, спустившись в каталоги с помощью нового Files.walk() . Вот как:
|
1
2
3
4
|
Files.walk(new File(".").toPath()) .filter(p -> !p.getFileName() .toString().startsWith(".")) .forEach(System.out::println); |
К сожалению, приведенное выше создаст поток путей, исключающий все скрытые файлы и каталоги, но их потомки все еще перечислены. Итак, мы получаем:
|
1
2
3
4
5
6
7
8
|
Omitted:.\.gitBut listed:.\.git\COMMIT_EDITMSG.\.git\config.\.git\description[...] |
Легко понять, почему это происходит. Files.walk() возвращает (ленивый) поток всех файлов-потомков. Вызов .filter() удалит те, которые скрыты от Stream, но это не влияет на рекурсивный алгоритм, который может применяться при реализации walk() . Честно говоря, это немного разочаровывает. Мы не можем использовать метод Java 7 Files.walkFileTree() , потому что принимающий тип FileVisitor не является @FunctionalInterface
Однако мы можем неэффективно обойти это ограничение с помощью следующей тривиальной логики:
|
1
2
3
4
|
Files.walk(new File(".").toPath()) .filter(p -> !p.toString() .contains(File.separator + ".")) .forEach(System.out::println); |
Это теперь дает ожидаемый
|
01
02
03
04
05
06
07
08
09
10
11
|
..\java8-goodies.iml.\LICENSE.txt.\pom.xml.\README.txt.\src.\src\main.\src\main\java.\src\main\java\org.\src\main\java\org\jooq[...] |
Хорошей новостью, однако, является новый Files.lines() . В следующем примере показано, как мы можем легко читать строку за строкой из файла, обрезая каждую строку (удаляя отступы) и отфильтровывая пустые:
|
1
2
3
4
|
Files.lines(new File("pom.xml").toPath()) .map(s -> s.trim()) .filter(s -> !s.isEmpty()) .forEach(System.out::println); |
Вышеуказанные выходы:
|
1
2
3
4
5
6
7
8
9
|
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<modelVersion>4.0.0</modelVersion><groupId>org.jooq</groupId><artifactId>java8-goodies</artifactId><version>1.0-SNAPSHOT</version>[...] |
Вывод
Понятно, что понятие «ленивая оценка» вызовет у сообщества большую путаницу, аналогично тому факту, что поток можно использовать только один раз. Мы делаем ставку на то, что API Java 8 Streams будет единственным источником новых вопросов о переполнении стека.
Тем не менее, Streams API будет потрясающим , и на следующей неделе в серии Java 8 в пятницу мы увидим, как мы можем использовать лямбда-выражения и Streams для сортировки , прежде чем увидим, как Java 8 улучшит взаимодействие с нашей базой данных!