Интерфейс StreamAPI. Конечные методы. Примеры использования. Методы collect(), count(), forEach(), max(), min(), reduce(), toArray()
Содержание
- 1. Метод collect(). Накопление элементов в контейнере. Пример
- 2. Метод count(). Получить количество элементов в потоке. Пример
- 3. Метод forEach(). Выполнить действие над каждым элементом потока. Пример
- 4. Метод max(). Вернуть максимальный элемент в потоке данных. Пример
- 5. Метод min(). Вернуть минимальный элемент в потоке данных. Пример
- 6. Метод reduce(). Получить указанный результат из элементов потока. Пример
- 7. Метод toArray(). Создать массив элементов в вызывающем потоке данных. Пример
- Связанные темы
Поиск на других ресурсах:
1. Метод collect(). Накопление элементов в контейнере. Пример
Метод collect() используется для накопления элементов из исходного потока в изменяющемся контейнере. Контейнером может быть, например, список, множество и тому подобное. Метод collect() называется операцией переменного сведения.
Общая форма метода следующая:
<R, A> R collect(Collector<? super T, A, R> collector)
здесь
- R – тип результирующего контейнера;
- T – тип элементов в исходном (вызывающем) потоке данных;
- A – внутренний накопительный тип;
- collector – функция накопления, представленная лямбда-выражением. Функция определяет порядок выполнения процесса накопления.
Метод collect() относится к конечным операциям (terminal operation).
Пример. В примере для потока чисел типа Double продемонстрированы следующие накопления элементов:
- извлечь из потока данных множество типа set<Double>. Для реализации этого используется метод-коллектор toSet() статического класса Collectors пакета java.util.stream;
- извлечь из потока данных список типа List<Double>. В этом случае используется метод toList() статического класса Collectors.
import java.util.*; import java.util.stream.*; public class StreamAPI { public static void main(String[] args) { // Метод collect() - накопление элементов в контейнере // 1. Создать набор чисел ArrayList<Double> AL = new ArrayList<Double>(); AL.add(1.5); AL.add(2.8); AL.add(-2.3); AL.add(3.4); AL.add(1.1); // 2. Получить поток данных из списка типа ArrayList<Double> Stream<Double> stream = AL.stream(); // 3. Выполнить обратную операцию - получить множество типа Set<Double> Set<Double> set; set = stream.collect(Collectors.toSet()); // метод collect() // 4. Вывести множество set на экран System.out.print("set = { "); for (Double t : set) System.out.print(t + " "); System.out.println("}"); // 5. Получить из множества set новый поток данных Stream<Double> stream2 = set.stream(); // 6. Получить из нового потока данных новый список типа List<Double> List<Double> AL2 = stream2.collect(Collectors.toList()); // 7. Вывести новый список на экран System.out.print("AL2 = [ "); for (Double t : AL2) System.out.print(t + " "); System.out.println("]"); } }
Результат выполнения программы
set = { 2.8 -2.3 1.5 3.4 1.1 } AL2 = [ 2.8 -2.3 1.5 3.4 1.1 ]
⇑
2. Метод count(). Получить количество элементов в потоке. Пример
Метод count() возвращает количество элементов в потоке. Общая форма метода
long count()
Метод count() есть конечной операцией.
Пример использования метода count().
import java.util.*; import java.util.stream.*; public class StreamAPI { public static void main(String[] args) { // Метод count() - получить количество элементов потока // 1. Создать набор чисел ArrayList<Double> AL = new ArrayList<Double>(); AL.add(1.5); AL.add(2.8); AL.add(-2.3); AL.add(3.4); AL.add(1.1); // 2. Получить поток данных Stream<Double> stream = AL.stream(); // 3. Получить количество элементов long count = stream.count(); System.out.println("count = " + count); } }
Результат выполнения программы
count = 5
⇑
3. Метод forEach(). Выполнить действие над каждым элементом потока. Пример
Метод forEach() применяется в случаях, когда над каждым элементом потока нужно выполнить некоторое действие (работу). Например, для удобного вывода значений элементов потока на экран.
Общая форма метода forEach() следующая:
void forEach(Consumer<? super T> action)
здесь
- Consumer<? super T> – тип, который является стандартным функциональным интерфейсом. В функциональном интерфейсе текущий тип элементов ограничивается некоторым типом T (? super T)
- action – лямбда-выражение, совершающее действие над отдельным элементом потока.
Метод forEach() есть конечной операцией (terminal operation).
Пример. В примере над каждым элементом потока выполняются следующие действия:
- умножить каждый элемент потока на 2;
- вывести каждый элемент потока на экран.
Для выполнения действия метод forEach() получает соответствующее лямбда-выражение, реализующее функциональный интерфейс Consumer<Double>.
import java.util.*; import java.util.stream.*; import java.util.function.*; public class StreamAPI { public static void main(String[] args) { // Метод forEach() - выполнить действие над каждым элементом потока // 1. Создать набор чисел ArrayList<Double> AL = new ArrayList<Double>(); AL.add(1.5); AL.add(2.8); AL.add(-2.3); AL.add(3.4); AL.add(1.1); // 2. Получить поток данных Stream<Double> stream = AL.stream(); // 3. Создать ссылку на стандартный функциональный интерфейс // Consumer<T> и присвоить ей лямбда-выражение Consumer<Double> action = (value) -> { value = value*2; // умножить каждый элемент потока на 2 System.out.print(value + " "); // вывести елемент на экран }; // 4. Использовать метод forEach() для вывода элементов потока на экран stream.forEach(action); } }
Результат выполнения программы
3.0 5.6 -4.6 6.8 2.2
⇑
4. Метод max(). Вернуть максимальный элемент в потоке данных. Пример
Метод max() предназначен для получения элемента с максимальным значением в потоке данных. Общая форма метода следующая:
Optional<T> max(Comparator<? super T> comparator)
здесь
- T – тип элементов потока данных;
- Optional<T> – результат, содержащий наибольшее значение элемента в потоке данных. Чтобы получить элемент нужно использовать метод get();
- comparator – функция сравнения двух значений типа T в виде лямбда-выражения;
- Comparator<? super T> – тип стандартного функционального интерфейса Java, используемого для сравнения двух значений обобщенного типа T.
Метод max() является конечной операцией.
Пример. В примере объявляется класс Circle, который реализует круг на координатной плоскости. Дополнительно формируется поток данных типа Circle. Для выходного потока данных определяется круг в котором наибольшая площадь.
import java.util.*; import java.util.stream.*; // Класс, реализующий окружность на координатной плоскости class Circle { // Внутренние поля класса private double x, y; // координата центра окружности private double radius; // радиус окружности // Конструктор public Circle(double x, double y, double radius) { this.x = x; this.y = y; this.radius = radius; } // Методы доступа public double getX() { return x; } public double getY() { return y; } public double getRadius() { return radius; } // Метод, возвращающий площадь окружности public double Area() { return Math.PI*radius*radius; } } public class StreamAPI { public static void main(String[] args) { // Метод max() - определяет наибольшее значение в потоке данных // 1. Создать набор данных типа Circle ArrayList<Circle> AL = new ArrayList<Circle>(); AL.add(new Circle(2.0, 5.0, 3.3)); AL.add(new Circle(2.5, 4.2, 3.1)); AL.add(new Circle(3.1, 4.1, 2.3)); AL.add(new Circle(4.0, 3.0, 4.3)); AL.add(new Circle(3.0, 2.0, 1.3)); // 2. Получить поток данных типа Circle из набора AL Stream<Circle> stream = AL.stream(); // 3. Объявить компаратор - метод сравнения двух значений типа Circle Comparator<Circle> comparator; // в лямбда-выражении нужно сравнить два экземпляра типа Circle comparator = (circle1, circle2) -> (int)(circle1.Area()-circle2.Area()); // 4. Найти окружность с наибольшей площадью Optional<Circle> maxCircle = stream.max(comparator); // 5. Вывести результат System.out.println("maxCircle = (" + maxCircle.get().getX() + "; " + maxCircle.get().getY() + "), radius = " + maxCircle.get().getRadius()); System.out.println("area = " + maxCircle.get().Area()); } }
Результат выполнения программы
maxCircle = (4.0; 3.0), radius = 4.3 area = 58.088048164875275
⇑
5. Метод min(). Вернуть минимальный элемент в потоке данных. Пример
Метод min() позволяет получить элемент с наименьшим значением в потоке данных. Общая форма метода имеет вид:
Optional<T> min(Comparator<? super T> comparator)
здесь
- T – тип элементов потока данных;
- Optional<T> – результат, содержащий наименьшее значение элемента в потоке данных. Чтобы получить элемент нужно использовать метод get();
- comparator — функция сравнения двух значений типа T, которая представлена лямбда-выражением;
- Comparator<? super T> — тип стандартного функционального интерфейса Java, используемого для сравнения двух значений обобщенного типа T.
Метод min() является конечной операцией.
Пример. В примере, на основе потока отрезков (линий), определяется отрезок с наименьшей длиной. В потоке данных каждый отрезок представлен экземпляром класса типа Line. Для конкретного отрезка задаются координаты точек его концов.
import java.util.*; import java.util.stream.*; // Класс, реализующий отрезок, заданный координатами точек (x1, y1), (x2, y2) class Line { // Внутренние поля класса private double x1, y1; private double x2, y2; // Конструктор public Line(double _x1, double _y1, double _x2, double _y2) { x1 = _x1; y1 = _y1; x2 = _x2; y2 = _y2; } // Методы доступа public double getX1() { return x1; } public double getY1() { return y1; } public double getX2() { return x2; } public double getY2() { return y2; } // Метод, возвращающий длину отрезка public double length() { return Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)); } } public class StreamAPI { public static void main(String[] args) { // Метод min() - получить минимальное значение элемента в потоке // 1. Создать набор отрезков типа Line ArrayList<Line> AL = new ArrayList<Line>(); AL.add(new Line(5.0, 6.0, 8.0, 9.5)); AL.add(new Line(1.1, 2.3, 8.1, 5.4)); AL.add(new Line(3.2, 2.8, 1.7, 4.4)); AL.add(new Line(6.1, 2.5, 3.1, 4.0)); AL.add(new Line(-1.2, 3.8, -4.3, 2.5)); // 2. Получить поток данных типа Line из набора AL Stream<Line> stream = AL.stream(); // 3. Объявить компаратор - метод сравнения двух значений типа Line Comparator<Line> comparator; comparator = (line1, line2) -> { // сравнить длины отрезков if (line1.length()>line2.length()) return 1; if (line1.length()<line2.length()) return -1; return 0; }; // 4. Найти линию с минимальным значением длины Optional<Line> minLine = stream.min(comparator); // 5. Вывести результат System.out.println("minLine = ( " + minLine.get().getX1() + "; " + minLine.get().getY1() + "), ( " + minLine.get().getX2() + "; " + minLine.get().getY2() + ")"); System.out.println("length = " + minLine.get().length()); } }
Результат выполнения программы:
minLine = ( 3.2; 2.8), ( 1.7; 4.4) length = 2.1931712199461315
⇑
6. Метод reduce(). Получить указанный результат из элементов потока. Пример
Метод reduce() относится к операциям сведения так же как методы min(), max(), count(). В методе reduce() можно свести поток к единому значению по собственно-разработанным критериям.
Примеры таких критериев:
- вычислить сумму элементов потока данных;
- вычислить произведение элементов потока данных;
- другие произвольные критерии.
Метод reduce() имеет несколько общих форм. Ниже приведены две наиболее популярные:
Optional<T> reduce(BinaryOperator<T> метод_накопления) T reduce(T значение_идентичности, BinaryOperator<T> метод_накопления)
здесь
- T — тип элементов потока;
- BinaryOperator<T> — тип стандартного функционального интерфейса, в котором содержится метод apply(). Стандартный функциональный интерфейс BinaryOperator<T> объявляется в пакете java.util.function;
- метод_накопления — это лямбда-выражение, реализующее функцию накопления. Функция накопления оперирует двумя значениями и возвращает некоторый результат;
- значение_идентичности — значение, приводящее к получению такого же значения элемента из потока данных. Например, если значение элемента равно x, то для операции суммирования значение_идентичности = 0 (0 + x = x). Для операции умножения значение_идентичности = 1 (1 * x = x).
При написании кода операции метод_накопления нужно придерживаться следующих ограничений:
- ограничение без сохранения состояния означает, что обработка каждого элемента потока осуществляется отдельно;
- ограничение без вмешательства означает, что источник данных не меняется в теле метода (операции);
- операция, применяемая к элементам потока, должна быть ассоциативна (a + b = b + a).
Метод reduce() является конечной операцией (terminated operation).
Пример. В примере определяется сумма элементов потока данных типа Double.
import java.util.*; import java.util.stream.*; import java.util.function.*; public class StreamAPI { public static void main(String[] args) { // Метод reduce() - использует функцию сведения к элементам потока // В примере вычисляется среднее арифметическое элементов потока данных // 1. Создать набор данных типа Double ArrayList<Double> AL = new ArrayList<Double>(); AL.add(25.0); AL.add(17.0); AL.add(33.0); AL.add(18.0); AL.add(27.0); AL.add(11.0); // 2. Получить поток данных типа Double из набора AL Stream<Double> stream = AL.stream(); // 3. Объявить бинарный оператор, возвращающий тип Double BinaryOperator<Double> accumulator; // 4. Для двух операндов реализовать вычисление суммы accumulator = (value1, value2) -> { return value1+value2; }; // 5. Вызвать функцию reduce() и вывести результат Optional<Double> sum = stream.reduce(accumulator); System.out.println("sum = " + sum.get()); } }
Результат выполнения программы
sum = 131.0
⇑
7. Метод toArray(). Создать массив элементов в вызывающем потоке данных. Пример
Метод toArray() предназначен для преобразования потока данных в массив типа Object[]. Метод имеет следующую общую форму:
Object[] toArray()
Метод является конечной операцией.
Пример. В примере поток данных типа Float конвертируется в массив типа Object[].
import java.util.*; import java.util.stream.*; import java.util.function.*; public class StreamAPI { public static void main(String[] args) { // Метод toArray() - конвертировать поток данных в массив типа Object[] // 1. Создать набор данных типа Float ArrayList<Float> AL = new ArrayList<Float>(); AL.add(25.0f); AL.add(11.3f); AL.add(3.8f); AL.add(7.7f); AL.add(2.4f); AL.add(5.5f); // 2. Получить поток данных типа Integer из набора AL Stream<Float> stream = AL.stream(); // 3. Получить массив типа Object[] из потока stream Object[] AF = stream.toArray(); // 4. Вывести результат System.out.print("AF = { "); for (int i=0; i<AF.length; i++) System.out.print(AF[i] + " "); System.out.println(" }"); } }
Результат выполнения программы
AF = { 25.0 11.3 3.8 7.7 2.4 5.5 }
⇑
Связанные темы
- Потоки данных Stream API. Общая информация
- Понятие конечной и промежуточной операции. Примеры. Отличия. Методы создания потока данных stream(), parallelStream()
- Интерфейс BaseStream. Примеры использования методов интерфейса
- Интерфейс Stream<T>. Промежуточные методы: filter(), map(), mapToDouble(), mapToInt(), mapToLong(), sorted(). Примеры
⇑