Для создания потока данных можно применять различные методы. В качестве источника потока мы можем использовать коллекции. В частности, в JDK 8 в интерфейс Collection, который реализуется всеми классами коллекций, были добавлены два метода для работы с потоками:
default Stream<E> stream
: возвращается поток данных из коллекции
default Stream<E> parallelStream
: возвращается параллельный поток данных из коллекции
Так, рассмотрим пример с ArrayList:
import java.util.stream.Stream; import java.util.*; public class Program { public static void main(String[] args) { ArrayList<String> cities = new ArrayList<String>(); Collections.addAll(cities, "Париж", "Лондон", "Мадрид"); cities.stream() // получаем поток .filter(s->s.length()==6) // применяем фильтрацию по длине строки .forEach(s->System.out.println(s)); // выводим отфильтрованные строки на консоль } }
Здесь с помощью вызова cities.stream()
получаем поток, который использует данные из списка cities. С помощью каждой промежуточной операции,
которая применяется к потоку, мы также можем получить поток с учетом модификаций. Например, мы можем изменить предыдущий пример следующим образом:
ArrayList<String> cities = new ArrayList<String>(); Collections.addAll(cities, "Париж", "Лондон", "Мадрид"); Stream<String> citiesStream = cities.stream(); // получаем поток citiesStream = citiesStream.filter(s->s.length()==6); // применяем фильтрацию по длине строки citiesStream.forEach(s->System.out.println(s)); // выводим отфильтрованные строки на консоль
Важно, что после использования терминальных операций другие терминальные или промежуточные операции к этому же потоку не могут быть применены, поток уже употреблен. Например, в следующем случае мы получим ошибку:
citiesStream.forEach(s->System.out.println(s)); // терминальная операция употребляет поток long number = citiesStream.count(); // здесь ошибка, так как поток уже употреблен System.out.println(number); citiesStream = citiesStream.filter(s->s.length()>5); // тоже нельзя, так как поток уже употреблен
Фактически жизненный цикл потока проходит следующие три стадии:
Создание потока
Применение к потоку ряда промежуточных операций
Применение к потоку терминальной операции и получение результата
Кроме вышерассмотренных методов мы можем использовать еще ряд способов для создания потока данных. Один из таких способов представляет метод Arrays.stream(T[] array), который создает поток данных из массива:
Stream<String> citiesStream = Arrays.stream(new String[]{"Париж", "Лондон", "Мадрид"}) ; citiesStream.forEach(s->System.out.println(s)); // выводим все элементы массива
Для создания потоков IntStream, DoubleStream, LongStream можно использовать соответствующие перегруженные версии этого метода:
IntStream intStream = Arrays.stream(new int[]{1,2,4,5,7}); intStream.forEach(i->System.out.println(i)); LongStream longStream = Arrays.stream(new long[]{100,250,400,5843787,237}); longStream.forEach(l->System.out.println(l)); DoubleStream doubleStream = Arrays.stream(new double[] {3.4, 6.7, 9.5, 8.2345, 121}); doubleStream.forEach(d->System.out.println(d));
И еще один способ создания потока представляет статический метод of(T..values) класса Stream:
Stream<String> citiesStream =Stream.of("Париж", "Лондон", "Мадрид"); citiesStream.forEach(s->System.out.println(s)); // можно передать массив String[] cities = {"Париж", "Лондон", "Мадрид"}; Stream<String> citiesStream2 =Stream.of(cities); IntStream intStream = IntStream.of(1,2,4,5,7); intStream.forEach(i->System.out.println(i)); LongStream longStream = LongStream.of(100,250,400,5843787,237); longStream.forEach(l->System.out.println(l)); DoubleStream doubleStream = DoubleStream.of(3.4, 6.7, 9.5, 8.2345, 121); doubleStream.forEach(d->System.out.println(d));