Перейти к основному содержимому

Потоки примитивного типа в Java 8

· 3 мин. чтения

1. Введение

Stream API был одной из ключевых функций, добавленных в Java 8.

Вкратце, API позволяет нам обрабатывать коллекции и другие последовательности элементов — удобно и более эффективно — за счет декларативного API.

2. Примитивные потоки

Потоки в основном работают с коллекциями объектов, а не с примитивными типами.

К счастью, для обеспечения возможности работы с тремя наиболее часто используемыми примитивными типами — int, long и double — стандартная библиотека включает три специализированные реализации примитивов: IntStream , LongStream и DoubleStream .

Примитивные потоки ограничены в основном из-за накладных расходов на упаковку и потому, что создание специализированных потоков для других примитивов во многих случаях не так уж полезно.

3. Арифметические операции

Давайте начнем с нескольких интересных методов для часто используемых арифметических операций, таких как min , max , sum и Average:

int[] integers = new int[] {20, 98, 12, 7, 35};
int min = Arrays.stream(integers)
.min()
.getAsInt(); // returns 7

Давайте теперь пройдемся по приведенному выше фрагменту кода, чтобы понять, что происходит.

Мы создали наш IntStream с помощью java.util.Arrays.stream(int[]) , а затем использовали метод min() для получения наименьшего целого числа как java.util.OptionalInt и, наконец, вызвали getAsInt() для получения значения int .

Другой способ создать IntStream — использовать IntStream.of(int…) . Метод max() вернет наибольшее целое число:

int max = IntStream.of(20, 98, 12, 7, 35)
.max()
.getAsInt(); // returns 98

Далее — чтобы получить сумму целых чисел, мы просто вызываем метод sum() , и нам не нужно использовать getAsInt() , так как он уже возвращает результат в виде значения int :

int sum = IntStream.of(20, 98, 12, 7, 35).sum(); // returns 172

Мы вызываем метод medium( ) , чтобы получить среднее значение целочисленных значений, и, как мы видим, мы должны использовать getAsDouble() , так как он возвращает значение типа double .

double avg = IntStream.of(20, 98, 12, 7, 35)
.average()
.getAsDouble(); // returns 34.4

4. Диапазон

Мы также можем создать IntStream на основе диапазона:

int sum = IntStream.range(1, 10)
.sum(); // returns 45
int sum = IntStream.rangeClosed(1, 10)
.sum(); // returns 55

Как показано в приведенном выше фрагменте кода, существует два способа создания диапазона целочисленных значений range() и rangeClosed() .

Разница в том, что конец range() является эксклюзивным, в то время как в rangeClosed() он включен .

Методы диапазона доступны только для IntStream и LongStream .

Мы можем использовать диапазон как причудливую форму цикла for-each:

IntStream.rangeClosed(1, 5)
.forEach(System.out::println);

Что хорошо в их использовании в качестве замены цикла for-each, так это то, что мы также можем воспользоваться преимуществом параллельного выполнения:

IntStream.rangeClosed(1, 5)
.parallel()
.forEach(System.out::println);

Какими бы полезными ни были эти причудливые циклы, все же лучше использовать традиционные циклы for вместо функциональных для простых итераций из-за простоты, удобочитаемости и производительности в некоторых случаях.

5. Упаковка и распаковка

Бывают случаи, когда нам нужно преобразовать примитивные значения в их эквиваленты-оболочки.

В этих случаях мы можем использовать метод boxed() :

List<Integer> evenInts = IntStream.rangeClosed(1, 10)
.filter(i -> i % 2 == 0)
.boxed()
.collect(Collectors.toList());

Мы также можем преобразовать поток класса-оболочки в примитивный поток:

// returns 78
int sum = Arrays.asList(33,45)
.stream()
.mapToInt(i -> i)
.sum();

Мы всегда можем использовать методы mapToXxx и flatMapToXxx для создания примитивных потоков.

6. Заключение

Java Streams — очень мощное дополнение к языку. Здесь мы едва коснулись примитивных потоков, но вы уже можете использовать их для продуктивной работы.

И, как всегда, образцы кода можно найти на GitHub .