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 .