Статьи

Java 8 Friday Goodies: новые новые API ввода / вывода

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

Ссылка: Java 8 Friday Goodies: новые новые API ввода / вывода от нашего партнера по JCG Лукаса Эдера в блоге JAVA, SQL и AND JOOQ .