Прошло несколько лет с тех пор, как была выпущена Java 8, и теперь Java перешла на 11, но изменения, внесенные в Java 8, можно назвать революционными и достаточно далеко идущими, чтобы изучение Java 8 должно было стать обязательным курсом для Java-разработчиков.
Сегодня я предлагаю вам объяснение потока Java 8. Почему я говорю об этом напрямую, так это то, что, как только вы закончите изучение, вы можете сразу же приступить к работе и заставить его работать в своем коде.
Стоит отметить, что вы должны узнать о lambda, прежде чем изучать Stream. В этой статье также предполагается, что читатель уже знаком с лямбда-выражениями..
Основное содержание этой статьи:
- Знакомство с потоками и как потоки работают с коллекциями
- Познакомить с взаимосвязью и различием между потоком и коллекцией.
- Введение в основные методы потока
1. Что такое поток
Поток называется на китайском"поток", путем декларативного преобразования коллекции в такую последовательность элементов, называемую «потоком», для каждого элемента коллекции может быть выполнена серия параллельных или последовательных итераций.Конвейерная обработка.
Другими словами, вам нужно только сказать потоку, что вы хотите, и поток будет обрабатывать элементы в соответствии с требованиями за кулисами, а вам просто нужно «сидеть и наслаждаться».
2. Потоковые операции
Вся потоковая операция представляет собой конвейер, в котором элементы размещаются для обработки один за другим.
Источником данных является исходная коллекция, а затем такая коллекция, как List, преобразуется в поток типа Stream, и над потоком выполняется ряд промежуточных операций, таких как фильтрация и сохранение некоторых элементов, сортировка элементов, преобразование типов, и т. д.; наконец, терминал выполняет операцию, вы можете преобразовать Stream обратно в тип коллекции, или вы можете напрямую обрабатывать каждый элемент в нем, например, печать, например, вычисление общего числа, вычисление максимального значения и т. д.
Важным моментом является то, что многие потоковые операции сами возвращают поток, поэтому несколько операций могут быть связаны напрямую.Давайте посмотрим на код потоковой операции:
В прошлом для выполнения такой последовательности операций вам нужно было сделать итератор или цикл foreach, а затем пройти, шаг за шагом, чтобы выполнить эти операции самостоятельно; но если вы используете потоки, вы можете напрямую использовать декларативные подземные инструкции, потоки поможет вам выполнить эти операции.
Вы думали о чем-то подобном? Да, точно так же, как операторы SQL,select username from user where id = 1
, вы просто заявляете: «Мне нужно, чтобы идентификатор был 1 (id = 1)Пользователь(user) имя пользователя (username)», то вы можете получить нужные данные без необходимости самостоятельно обращаться к базе данных для выполнения поиска.
3. Потоки и коллекции
когда рассчитывать
Одно из различий между потоками и коллекциями заключается в том, когда выполняются вычисления.
Набор, который содержит все значения в текущей структуре данных, вы можете добавить или удалить в любой момент, но элементы в наборе, несомненно, уже вычислены.
Поток рассчитывается по запросу, а данные рассчитываются в соответствии с потребностями пользователя.Вы можете себе представить, что мы ищем через поисковую систему.Отображаются не все искомые элементы, а отображаются первые 10 или 20 наиболее подходящих элементов. Только когда вы нажмете «Далее», будут выведены новые 10.
Например, просмотр фильмов онлайн и фильмов на жестком диске похожи.
Внешняя итерация и внутренняя итерация
Еще одно различие между потоками и коллекциями — это итерация.
Мы можем сравнить сбор со складом фабрики.Вначале фабрика была относительно отсталой.Чтобы внести изменения в товары, только рабочие могли лично ходить на склад для обработки товаров, а иногда помещали обработанные товары в новый склад внутри склада. В этот период нам нужно самим делать итерации, по одному находить нужные нам товары и обрабатывать их, что называетсявнешняя итерация.
Позже фабрика развивалась и была оснащена сборочной линией.Поскольку соответствующая сборочная линия была спроектирована в соответствии с потребностями, то рабочим нужно было только поставить товар на сборочную линию, а затем они могли ждать, чтобы получить результаты. , а сборочная линия может напрямую доставлять товары на соответствующее оборудование в соответствии с требованиями склада. это называетсявнутренняя итерация, конвейер уже помог вам завершить итерацию, вам нужно только сказать, что делать (т. е. спроектировать разумный конвейер).
Java 8 представила Stream в значительной степени, потому что внутренняя итерация потока может автоматически выбирать представление данных и параллельную реализацию, подходящую для вашего оборудования; в прошлом, когда программисты сами делали foreach, им нужно было самостоятельно управлять параллелизмом и другими проблемами. .
одноразовый поток
Потоки похожи на итераторы тем, что их можно повторить только один раз.
Stream<String> stream = list.stream().map(Person::getName).sorted().limit(10);
List<String> newList = stream.collect(toList());
List<String> newList2 = stream.collect(toList());
Третья строка в приведенном выше коде сообщит об ошибке, потому что вторая строка уже использовала поток, а поток был потреблен.
4. Способ введения, начать фактический бой
Сначала мы создаем общий список лиц.
List<Person> list = new ArrayList<>();
list.add(new Person("jack", 20));
list.add(new Person("mike", 25));
list.add(new Person("tom", 30));
Класс Person содержит две переменные-члены: возраст и имя.
private String name;
private int age;
1. stream() / parallelStream()
Наиболее часто используемый метод преобразования коллекции в поток
List list = new ArrayList();
// return Stream<E>
list.stream();
И parallelStream() — это метод параллельного потока, который позволяет набору данных выполнять параллельные операции, которые будут объяснены более подробно позже.
2. filter(T -> boolean)
сохранить элементы, для которых логическое значение истинно
保留年龄为 20 的 person 元素
list = list.stream()
.filter(person -> person.getAge() == 20)
.collect(toList());
打印输出 [Person{name='jack', age=20}]
collect(toList()) может преобразовать поток в тип List, что будет объяснено позже.
3. distinct()
Удалить повторяющиеся элементы. Этот метод предназначен для определения равенства двух элементов с помощью метода equals класса.
Например, класс Person в этом примере должен сначала определить метод equals, в противном случае он аналогичен[Person{name='jack', age=20}, Person{name='jack', age=20}]
Эта ситуация не будет обработана
4. sorted() / sorted((T, T) -> int)
Если класс элементов в потоке реализует интерфейс Comparable, то есть имеет свои правила сортировки, то для сортировки элементов можно напрямую вызвать метод sorted(), например Stream
Вместо этого вам нужно позвонитьsorted((T, T) -> int)
Реализовать интерфейс компаратора
根据年龄大小来比较:
list = list.stream()
.sorted((p1, p2) -> p1.getAge() - p2.getAge())
.collect(toList());
Конечно, это можно упростить до
list = list.stream()
.sorted(Comparator.comparingInt(Person::getAge))
.collect(toList());
5. limit(long n)
Возвращает первые n элементов
list = list.stream()
.limit(2)
.collect(toList());
打印输出 [Person{name='jack', age=20}, Person{name='mike', age=25}]
6. skip(long n)
удалить первые n элементов
list = list.stream()
.skip(2)
.collect(toList());
打印输出 [Person{name='tom', age=30}]
tips:
- При использовании перед limit(n) удалите первые m элементов и верните первые n элементов из оставшихся элементов.
- Когда limit(n) используется перед skip(m), он возвращает первые n элементов, а затем удаляет m элементов из оставшихся n элементов.
list = list.stream()
.limit(2)
.skip(1)
.collect(toList());
打印输出 [Person{name='mike', age=25}]
7. map(T -> R)
сопоставить каждый элемент T в потоке с R (например, преобразование типа)
List<String> newlist = list.stream().map(Person::getName).collect(toList());
Элементы в новом списке — это переменные имени каждого объекта Person в списке.
8. flatMap(T -> Stream)
Сопоставьте каждый элемент T в потоке с потоком и подключите каждый поток к потоку.
List<String> list = new ArrayList<>();
list.add("aaa bbb ccc");
list.add("ddd eee fff");
list.add("ggg hhh iii");
list = list.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(toList());
В приведенном выше примере наша цель состоит в том, чтобы разделить каждый строковый элемент в списке с помощью " " и превратить его в новый список.
Во-первых, метод map разделяет каждый строковый элемент, но в это время тип потока — StreamArrays::stream
Превратите каждый элемент String[] в поток Stream, затем flatMap объединит каждый поток в поток и, наконец, вернет нужный нам поток.
9. anyMatch(T -> boolean)
соответствует ли элемент в потоке заданномуT -> boolean
состояние
是否存在一个 person 对象的 age 等于 20:
boolean b = list.stream().anyMatch(person -> person.getAge() == 20);
10. allMatch(T -> boolean)
соответствуют ли все элементы в потоке заданномуT -> boolean
состояние
11. noneMatch(T -> boolean)
не соответствует ли ни один элемент в потоке заданномуT -> boolean
состояние
12. найтиЛюбой() и найтиПервый()
- findAny(): находит один из элементов (первый элемент находится при использовании stream(); один из элементов находится при использовании parallelStream())
- findFirst(): найти первый элемент
Стоит отметить, что эти два метода возвращают необязательный объект., это класс-контейнер, который может представлять наличие или отсутствие значения, что будет рассмотрено позже.
13. уменьшить ((T, T) -> T) и уменьшить (T, (T, T) -> T)
Используется для объединения элементов в поток, таких как сумма, произведение, максимум и т. д.
计算年龄总和:
int sum = list.stream().map(Person::getAge).reduce(0, (a, b) -> a + b);
与之相同:
int sum = list.stream().map(Person::getAge).reduce(0, Integer::sum);
Среди них первый параметр 0 сокращения представляет собой начальное значение 0, а лямбда(a, b) -> a + b
то есть добавление двух значений для получения нового значения
Так же:
计算年龄总乘积:
int sum = list.stream().map(Person::getAge).reduce(1, (a, b) -> a * b);
Конечно вы можете
Optional<Integer> sum = list.stream().map(Person::getAge).reduce(Integer::sum);
То есть он не принимает никакого начального значения, а поскольку начального значения нет, то необходимо учитывать ситуацию, что результата может не быть, поэтому он возвращает необязательный тип
13. count()
Возвращает количество элементов в потоке в виде длинного
14. collect()
Метод сбора, который мы обычно используем, этоcollect(toList())
, и конечноcollect(toSet())
Подождите, параметр представляет собой интерфейс коллектора, о котором будет рассказано позже.
15. forEach()
Возвращаемый результат недействителен, и очевидно, что мы можем с ним сделать, например:
### 16. unordered()
还有这个比较不起眼的方法,返回一个等效的无序流,当然如果流本身就是无序的话,那可能就会直接返回其本身
打印各个元素:
list.stream().forEach(System.out::println);
Другим примером является метод сопоставления для доступа к базе данных в MyBatis:
向数据库插入新元素:
list.stream().forEach(PersonMapper::insertPerson);
Связанное Чтение
Вам также может понравиться
- Вы должны выяснить String, StringBuilder, StringBuffer
- Поделитесь некоторыми личными галантереями бэкэнда Java
- Научу вас Shiro + SpringBoot интегрировать JWT
- Научу вас Широ интегрировать SpringBoot и избегать всевозможных ям