В 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: .\.git But 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 улучшит взаимодействие с нашей базой данных!