Научитесь создавать и работать с потоками примитивных типов в Java на примерах.
1. Примитивы и классы-оболочки
Java не является настоящим объектно-ориентированным языком программирования и поддерживает примитивные типы, которые не являются объектами. У нас есть 7 примитивов в Java, которые являются byte, short, int, long, double, float, char.
Java позволяет обернуть их в объекты( классы-обертки ), так что эти типы могут быть представлены как объекты, когда это необходимо. Соответствующие классы-обертки — Byte, Short, Integer, Long, Double, Float и Char.
Процесс преобразования примитива в объект называется автоупаковкой, а преобразование объекта в примитив называется распаковкой.
2. Поддержка примитивных потоков
Java Stream API, подобно Collections API, был разработан для работы с объектами, а не с примитивными типами.
API потока имеет встроенную поддержку для представления примитивных потоков с использованием следующих специализированных классов. Все эти классы поддерживают последовательные и параллельные агрегатные операции над элементами потока.
- IntStream: представляет собой последовательность примитивных целочисленных элементов.
- LongStream: представляет собой последовательность примитивных длиннозначных элементов.
- DoubleStream: представляет собой последовательность примитивных элементов с двойным значением.
Эти классы помогают избежать множества ненужных операций по созданию объектов, автоматической упаковке и распаковке, если мы решим выполнять эти операции самостоятельно.
Для других примитивных типов Java не предоставляет подобных классов поддержки потоков, поскольку не было найдено полезным иметь так много классов. Типы int, long и double очень часто используются, поэтому для них была добавлена поддержка.
3. Создание потоков примитивов
3.1 Создание потока указанных значений
Если у нас есть несколько указанных значений int, long или double, то мы можем создать поток с помощью фабричного метода of().
IntStream stream = IntStream.of(1, 2, 3, 4, 5);LongStream stream = LongStream.of(1, 2, 3, 4, 5);DoubleStream stream = DoubleStream.of(1.0, 2.0, 3.0, 4.0, 5.0);
3.2. Метод Fatory Stream.range()
Метод range() возвращает последовательный упорядоченный IntStream или LongStream от startInclusive(включительно) до endExclusive(исключительно) с шагом 1.
IntStream stream = IntStream.range(1, 10); //1,2,3,4,5,6,7,8,9LongStream stream = LongStream.range(10, 100);
Похожий метод rangeClosed() также возвращает последовательный упорядоченный поток, но конечный элемент входит в поток.
IntStream stream = IntStream.rangeClosed(1, 10); //1,2,3,4,5,6,7,8,9,10
3.3. Массивы.stream()
Мы можем напрямую вызвать метод stream() для массива, который вернет экземпляр класса Stream, соответствующий типу массива.
Например, если мы вызовем array.stream() для int[], то он вернет экземпляр IntStream.
// int[] -> Streamint[] array = new int[]{1, 2, 3, 4, 5};IntStream stream = Arrays.stream(array);// long[] -> Streamlong[] array = new long[]{1, 2, 3, 4, 5};LongStream stream = Arrays.stream(array);// double[] -> Streamdouble[] array = new double[]{1.0, 2.0, 3.0, 4.0, 5.0};DoubleStream stream = Arrays.stream(array);
3.4 Поток mapToInt(), mapToLong() и mapToDouble()
Другой метод получения примитивного потока — использование функции mapTo() для соответствующего типа.
Например, если у нас есть поток целых чисел или любой другой тип объекта с полем целого типа(например, возраст человека), то мы можем получить поток всех таких значений как поток целых значений.
List<Integer> integerList = List.of(1, 2, 3, 4, 5);IntStream stream = integerList.stream().mapToInt(i -> i);Stream<Employee> streamOfEmployees = getEmployeeStream();DoubleStream stream = streamOfEmployees.mapToDouble(e -> e.getSalary());
4. Нахождение суммы, среднего, максимума и минимума
4.1 Встроенные методы
Все три класса, IntStream, LongStream и DoubleStream, состоят из числовых значений, и имеет смысл предоставить встроенную поддержку общих агрегатных операций над элементами потока.
Эти классы предоставляют следующие методы для этих операций. Типы возвращаемых данных соответствуют типу потока. Следующие методы взяты из класса IntStream:
- sum() – возвращает сумму элементов в потоке.
- average() – возвращает OptionalDouble, описывающий среднее арифметическое элементов потока.
- max() – возвращает OptionalInt, описывающий максимальный элемент потока.
- min() – возвращает OptionalInt, описывающий минимальный элемент потока.
- count() – возвращает количество элементов в потоке.
Давайте рассмотрим несколько примеров использования этих методов.
int max = IntStream.of(10, 18, 12, 70, 5).max().getAsInt();double avg = IntStream.of(1, 2, 3, 4, 5).average().getAsDouble();int sum = IntStream.range(1, 10).sum();
4.2.Сводная статистика
Другой способ найти указанные выше статистические данные — использовать метод summaryStatistics(), который возвращает один из следующих классов:
- IntSummaryСтатистика
- LongSummaryСтатистика
- DoubleSummaryСтатистика
Теперь мы можем использовать его методы для получения требуемого значения.
- получитьСреднее()
- получитьКоличество()
- получитьМакс()
- получитьМин()
- получитьСумму()
IntSummaryStatistics summary = IntStream.of(10, 18, 12, 70, 5).summaryStatistics();int max = summary.getMax();
5. Примитивный поток в объектный поток
Используя метод boxed(), мы можем преобразовать примитивный поток в объектный поток соответствующего типа.
Например, чтобы получить Stream<Long> из LongStream, мы можем вызвать метод boxed():
Stream<Integer> boxedStream1 = IntStream.of(1, 2, 3, 4, 5).boxed();Stream<Long> boxedStream = LongStream.of(1, 2, 3, 4, 5).boxed();Stream<Double> boxedStream2 =DoubleStream.of(1.0, 2.0, 3.0, 4.0, 5.0).boxed();
6. Заключение
В этом уроке мы поняли, какую поддержку поток примитивов поддерживает Java. Мы изучили различные способы создания потоков примитивов, а затем научились выполнять некоторые общие числовые операции над элементами потока.
Мы также научились получать упакованные потоки и сводную статистику.