В предыдущих статьях о Stream API объекты Stream всегда создавались из Iterable, вызовами stream() или parallelStream(). Однако существуют и другие источники создания Stream.
Stream из файла
В примере с подсчётом числа фильмов, выпущенных в тот или иной год, файл с данными вначале читался в память, в List<String>, и обрабатывался уже из памяти. Это был совершенно лишний шаг, потому что Stream можно создать напрямую из файла:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public static void main(final String[] args) throws IOException {
new BufferedReader(new InputStreamReader(SingleStreamMovies.class
.getClassLoader()
.getResourceAsStream("movies.list")))
.lines()
.map(YEAR_PATTERN::matcher)
.filter(Matcher::matches)
.map(m -> m.group(1))
.map(Integer::parseInt)
.sorted()
.collect(
Collectors.groupingBy(i -> i,
LinkedHashMap::new,
Collectors.counting()))
.forEach((k, v) -> System.out.println(k + ":" + v));
}
|
Для файлов, которые хранятся в файловой системе и для которых есть известный путь, можно использовать класс Files:
1
2
3
4
5
|
Files
.lines(
new File("/tmp/movies.list")
.toPath())
.count
|
Stream из списка файлов
В классе Files существуют и другие методы, возвращающие объект Stream.
Поиск файлов, соответствующих условию:
1
2
3
4
5
6
|
Files.find(
new File("/")
.toPath(),
0,
(p, a) -> a.isDirectory())
.count();
|
Или просмотр заданного каталога и отбор записей, соответствующих условию:
1
2
3
4
5
|
Files.list(
new File(path)
.toPath())
.filter(p -> p.toFile().isDirectory())
.count();
|
Обход всего дерева, начиная с заданной позиции:
1
2
3
4
|
return Files.walk(new File("/").toPath())
.filter(p -> p.toFile().isFile())
.filter(p -> p.getFileName().startsWith("S"))
.count();
|
Генерация данных
Самый лучший Stream, из случайных чисел:
1
2
3
4
5
6
7
|
public void RandomPrimes() {
new Random()
.ints()
.filter(PrimeNumbers::isPrime)
.limit(10)
.forEach(System.out::println);
}
|
Или из диапазона целых чисел:
1
2
3
4
5
6
|
public Integer rangePrimeMax() {
return IntStream.range(1,100)
.filter(PrimeNumbers::isPrime)
.summaryStatistics()
.getMax();
}
|
Или из функции:
1
2
3
4
5
6
7
8
9
10
|
public Integer randomSeriesPrimes() {
Random r = new Random();
Optional<Integer> result = Stream.iterate(2,o -> o+r.nextInt())
.filter(PrimeNumbers::isPrime)
.findAny();
if (!result.isPresent()) {
return 0;
}
return result.get();
}
|
Stream из массива
Любой массив объектов можно преобразовать в Stream:
1
2
3
4
5
6
|
public long averageArray() {
return Arrays.stream(numbers)
.mapToInt(i -> i)
.summaryStatistics()
.getSum();
}
|
Или список аргументов:
1
2
3
4
5
6
|
public double avarageLorem() {
return Stream.<String>of("Lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit", "Curabitur", "vestibulum")
.mapToInt(s -> s.length())
.summaryStatistics()
.getAverage();
}
|
Кроме использования стандартных методов создания Stream, можно реализовывать собственные источники данных для Stream, используя низкоуровневый интерфейс Spliterator, но этому будет посвящена отдельная статья.
Код примера доступен на github. Для исполнения требуется скачать IMDB movies.list и положить его в src/resources.