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

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

Мы вызываем метод average () , чтобы получить среднее целочисленных значений, и, как мы видим, мы должны использовать 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 .

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

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

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

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 - очень мощное дополнение к языку. Мы едва поцарапали поверхность примитивных потоков здесь, но, как вы уже можете использовать их, чтобы быть продуктивными.

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