Я начал пробовать использовать новые возможности Java полгода назад, и больше всего меня впечатлили Stream и Optional. Среди них Stream повышает эффективность просмотра и делает код очень чистым.
Зачем использовать потоки?
Это было объяснено в аннотации, чтобы повысить эффективность разработки. Потоки помогают нам работать эффективно集合
, поток помогает нам пройти流水线
способ выполнить сбор删减
,合并
,排序
,修改
и, наконец, вернуть данные элемента или статистику, которые нам нужны.流水线
Это означает, что партия элементов не должна ждать, пока все элементы завершат определенный шаг, прежде чем перейти к следующему шагу, но может перейти к следующему шагу как можно скорее, как сборочная линия, которая обеспечивает основу. для эффективной работы потока. поток и еще один内部迭代
Идея состоит в том, чтобы скрыть итерацию отображения цикла for, что может быть более удобным.并行开发
.
использование потоков
Подготовить
Прежде чем использовать поток, вам нужно сделать некоторые приготовления.Во-первых, объясняются две концепции:中间操作
и终端操作
.中间操作
Это похоже на пошаговую обработку элемента в производственном цеху, после каждого шага может меняться стиль элемента или структура данных в нем, но это все равно поток.终端操作
Продукт как бы закончен, и его нужно упаковать в коробку, чтобы он стал окончательным, видимым конечному потребителю, в это время это уже продукт, а не поток.
Затем, чтобы продемонстрировать операцию, сначала смоделируйте несколько фрагментов данных.
List<JSONObject> menu = new ArrayList<>();
menu.add(new JSONObject().putOpt("name","宫保鸡丁").putOpt("price","28"));
menu.add(new JSONObject().putOpt("name","鱼香肉丝").putOpt("price","30"));
menu.add(new JSONObject().putOpt("name","肉夹馍").putOpt("price","6"));
menu.add(new JSONObject().putOpt("name","煎饼").putOpt("price","6"));
Часто используемые промежуточные операции
filter
Фильтр должен быть наиболее распространенным в потоковых операциях. Как следует из названия, фильтр используется для фильтрации данных. Параметр фильтра может быть лямбда-выражением.
//比如下面这句话,就是得到所有价格小于10的食物,得到的还是流。
//stream()方法将集合转成流
menu.stream().filter(jsonObject -> jsonObject.getInt("price")<10);
отличить, ограничить и пропустить
Different — удалить дубликаты, limit — перехватить первые несколько элементов, а skip — пропустить первые несколько элементов.
List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(1);
integerList.add(2);
integerList.add(3);
integerList.stream()
.distinct()//经过去重,流还剩1、2、3
.skip(1)//跳过第一个元素,流中还有2、3
.limit(1);//截取第一个元素,流中还剩2
map
отображение карты, фильтр выше предназначен для фильтрации элементов, а карта предназначена для изменения стиля элементов. Например, мы хотим знать названия всех продуктов, которых меньше 10 штук.
menu.stream()
.filter(jsonObject -> jsonObject.getInt("price")<10)//此时还是jsonObject
.map(jsonObject -> jsonObject.getStr("name"));//此时变成了String
flatMap
Слияние потоков может объединять несколько массивов, так что возвращаемый элемент является не потоком, а самим конкретным элементом.
Stream.of(menu,foreignMenu)//此时元素是流 List<Stream>
.flatMap(x -> x.stream())//此时元素是jsonObject List<jsonObject>
.map(jsonObject -> jsonObject.getStr("name"))
.distinct();
Общие терминальные методы
allMatch, anyMatch, noneMatch, findFirst и findAny
метод | имея в виду |
---|---|
allMatch | Проверить, соответствует ли предикат всем элементам |
anyMatch | Проверить, соответствует ли предикат хотя бы одному элементу |
noneMatch | Убедитесь, что ни один элемент в потоке не соответствует заданному предикату |
findFirst | Найдите первый соответствующий элемент |
findAny | вернет любой элемент в текущем потоке |
//前三个方法都是返回boolean类型
boolean allMatchBool = menu.stream()
.allMatch(jsonObject -> jsonObject.getInt("price") < 10);
boolean noneMatchBool = menu.stream()
.noneMatch(jsonObject -> jsonObject.getInt("price") < 10);
boolean anyMatchBool = menu.stream()
.anyMatch(jsonObject -> jsonObject.getInt("price") < 10);
Приведенные выше методы возвращают логические типы, а findFirst и findAny возвращают элементы.
//关于Optional,先不关心,总之是元素就对了
Optional<JSONObject> first = menu.stream().findFirst();
Optional<JSONObject> any = menu.stream().findAny();
System.out.println(first.get().toString());
System.out.println(any.get().toString());
//输出
//{"price":"28","name":"宫保鸡丁"}
//{"price":"28","name":"宫保鸡丁"}
Для двух вышеуказанных методов, если найдены данные, соответствующие условиям, поток завершается раньше. Почему выводятся первые элементы, а добиться этого можно двумя способами? так как并行
, findAny будет менее ограничивающим с точки зрения параллелизма.
reduce
Как я сказал в начале, окончательное возвращаемое значение может быть набором элементов или статистическими данными (или индукцией), такими как суммирование элементов. Предположим, нам нужноmenu
Сколько стоит одна порция всей еды в .
Optional<Integer> price = menu.stream()//List<JsonObject>
.map(jsonObject -> jsonObject.getInt("price"))//先将元素转成数字List<Integer>
.reduce((x, y) -> x + y);
System.out.println(price.get());
макс и мин
Это легко понять, это максимальное и минимальное значения. Эффект похож на
.reduce(Integer::max)
.reduce(Integer::min)
Резюме общих потоков
Легко понять, что sorted и count не отображаются. Что касается сбора, то он используется больше.
преобразование потока
В дополнение к объектному потоку (Stream) есть также некоторые потоки типов, такие как IntStream (возьмем в качестве примера IntStream, другие аналогичны) Приведенное выше суммирование возвращает необязательный объект, может ли оно напрямую возвращать тип Integer?
//使用映射方法mapToInt()就ok了
int price = menu.stream()//Stream
.mapToInt(jsonObject -> jsonObject.getInt("price"))//IntStream
.sum();
//类型流转化回对象流,可以使用boxed()
IntStream intStream = menu.stream()
.mapToInt(jsonObject -> jsonObject.getInt("price"));
Stream<Integer> boxed = intStream.boxed();
//当然了IntStream中有很多int类型操作的方法,就不一一举例了,源码打开一看,见名知意
коллекционер
Для общих промежуточных операций, упомянутых выше, возвращаемые значения — это все потоки, а для некоторых операций прерывания все возвращаемые значения — необязательные или числовые значения. Не забывайте, что первоначальным намерением Stream было решить проблему операций сбора. Наконец, он преобразуется в операцию прерывания collect, используемую коллекцией, а параметром является интерфейсCollector
, существует много методов преобразования.
конвертировать в набор
Наиболее часто используется метод toList(), который превращает возвращаемый результат в список.
List<JSONObject> list = menu.stream()
.filter(jsonObject -> jsonObject.getInt("price") < 10)
.collect(Collectors.toList());
//当然还有toSet()等等,触类旁通
Конкатенация строк
Чаще всего используется ссылка на строку. Использование метода присоединения()
String s = menu.stream()
.filter(jsonObject -> jsonObject.getInt("price") < 10)
.map(jsonObject -> jsonObject.getStr("name"))
.collect(Collectors.joining(","));
группировка
Сгруппируйте по предоставленным атрибутам, используйте groupingBy() , для удобства описания присвойте вышеуказанным различным продуктам значение типа:
List<JSONObject> menu = new ArrayList<>();
menu.add(new JSONObject().putOpt("name","宫保鸡丁").putOpt("price","28").putOpt("type","good"));
menu.add(new JSONObject().putOpt("name","鱼香肉丝").putOpt("price","30").putOpt("type","good"));
menu.add(new JSONObject().putOpt("name","肉夹馍").putOpt("price","6").putOpt("type","normal"));
menu.add(new JSONObject().putOpt("name","煎饼").putOpt("price","6").putOpt("type","normal"));
Map<String, List<JSONObject>> type = menu.stream()
.collect(Collectors.groupingBy(jsonObject -> jsonObject.getStr("type")));
System.out.println(type);
//输出
//{normal=[{"price":"6","name":"肉夹馍","type":"normal"}, {"price":"6","name":"煎饼","type":"normal"}], good=[{"price":"28","name":"宫保鸡丁","type":"good"}, {"price":"30","name":"鱼香肉丝","type":"good"}]}
Похож на группировку, есть еще метод partitioningBy(), разбиение, но его параметры находятся вboolean
тип.
мой публичный аккаунт
Мой официальный аккаунт используется для синхронизации блога