1. Введение
вчера вОперация удаления элемента коллекцииупоминается в соответствующей статьеCollectors
. Я считаю, что многих студентов это больше интересует, поэтому давайте сегодня изучим этоCollectors
.
2. Роль коллекционеров
Collectors
даJava 8Добавленный класс операции находится вjava.util.stream
под пакет. В нем будет обобщен сбор элементов по разным стратегиям, например, самый простой и распространенный — поместить элементы вMap
,Set
,List
и т. д. в изменяемом контейнере. специально дляJava 8 Stream Apiочень полезно. Это обеспечиваетcollect()
путь кStream
Потоки выполняют операции завершения для получения наборов результатов на основе различных стратегий. мы полагаемся наStream
познакомитьсяCollectors
Бар. Мы по-прежнему используем вчерашний пример:
List<String> servers = new ArrayList<>();
servers.add("Felordcn");
servers.add("Tomcat");
servers.add("Jetty");
servers.add("Undertow");
servers.add("Resin");
3. Методы коллекторов в Java 8
Collectors
Нам предоставляется ряд статических методов, обычно мы можем использовать статический импорт. Далее, давайте посмотрим, какие методы предусмотрены.
3.1 Тип индукции
Это серия, которая разделяет элементы на изменяемый контейнер.List
,Map
,Set
,Collection
илиConcurrentMap
.
Collectors.toList();
Collectors.toMap();
Collectors.toSet();
Collectors.toCollection();
Collectors.toConcurrentMap();
Мы можем предоставить вышеAPIиспользоватьStream
изcollect
Преобразование в методе к знакомому контейнеру-коллекции. Очень просто и не будет здесь демонстрироваться.
3.2 joining
Соединяйте элементы по некоторым правилам. Есть три перегрузки этого методаjoining(CharSequence delimiter)
иjoining(CharSequence delimiter,CharSequence prefix,CharSequence suffix)
// 输出 FelordcnTomcatJettyUndertowResin
servers.stream().collect(Collectors.joining());
// 输出 Felordcn,Tomcat,Jetty,Undertow,Resin
servers.stream().collect(Collectors.joining("," ));
// 输出 [Felordcn,Tomcat,Jetty,Undertow,Resin]
servers.stream().collect(Collectors.joining(",", "[", "]"));
Чаще используется для чтенияHttpServletRequest
серединаbody:
HttpServletRequest.getReader().lines().collect(Collectors.joining());
3.3 collectingAndThen
Метод сначала выполняет операцию индукции, а затем выполняетFunction
Функция process выводит новый результат.
// 比如我们将servers joining 然后转成大写,结果为: FELORDCN,TOMCAT,JETTY,UNDERTOW,RESIN
servers.stream.collect(Collectors.collectingAndThen(Collectors.joining(","), String::toUpperCase));
3.4 groupingBy
группировать элементы по условию иSQLсерединаgroup by
Использование имеет тот же эффект, и обычно рекомендуется использоватьJavaГрупповая обработка для снижения нагрузки на базу данных.groupingBy
Также есть три перегруженных метода
мы будемservers
Сгруппировать по длине:
// 按照字符串长度进行分组 符合条件的元素将组成一个 List 映射到以条件长度为key 的 Map<Integer, List<String>> 中
servers.stream.collect(Collectors.groupingBy(String::length))
если я не хочуMap
изvalue
заList
что делать? Приведенная выше реализация фактически вызывает следующий метод:
//Map<Integer, Set<String>>
servers.stream.collect(Collectors.groupingBy(String::length, Collectors.toSet()))
Что, если мне придется учитывать вопросы безопасности синхронизации? Конечно, используйте потокобезопасный контейнер синхронизации, тогда первые два использовать нельзя! Не волнуйтесь! Давайте сделаем вывод, что второе на самом деле эквивалентно следующему написанию:
Supplier<Map<Integer,Set<String>>> mapSupplier = HashMap::new;
Map<Integer,Set<String>> collect = servers.stream.collect(Collectors.groupingBy(String::length, mapSupplier, Collectors.toSet()));
Это очень легко сделать, мы предоставляем синхронизациюMap
Нет, это нормально, так что проблема решена:
Supplier<Map<Integer, Set<String>>> mapSupplier = () -> Collections.synchronizedMap(new HashMap<>());
Map<Integer, Set<String>> collect = servers.stream.collect(Collectors.groupingBy(String::length, mapSupplier, Collectors.toSet()));
На самом деле вопросы безопасности синхронизацииCollectors
другой методgroupingByConcurrent
дает нам решение. использование иgroupingBy
почти.
3.5 partitioningBy
partitioningBy
Мы уже видели это в статье, упомянутой в начале этой статьи, которую можно рассматривать какgroupingBy
Частный случай , основанный на утверждении (Predicate
) группировка политик. Дополнительные примеры здесь не приводятся.
3.6 counting
Этот метод суммирует количество элементов, что очень просто и не будет проиллюстрировано.
3.7 maxBy/minBy
Эти два метода обеспечивают операции по нахождению элементов размера соответственно, и они основаны на интерфейсе компаратораComparator
для сравнения, он возвращаетOptional
объект. давайservers
Элемент с наименьшей длиной в:
// Jetty
Optional<String> min = servers.stream.collect(Collectors.minBy(Comparator.comparingInt(String::length)));
На самом деле здесьResin
Длина также наименьшая, и здесь соблюдается принцип «предвзятости». КонечноStream.min()
Очень удобно получить элемент минимальной длины.maxBy
То же самое.
3.8 summingInt/Double/Long
Используется для кумулятивных расчетов. Вычислить сумму атрибута элемента, подобногоMysqlизsum
Функции, такие как подсчет общей прибыли каждого проекта, подсчет суммы всех зарплат за месяц и так далее. Давайте посчитаем здесьservers
Сумма длин строк в (другие способы записи для примера не рассматриваются).
// 总长度 32
servers.stream.collect(Collectors.summingInt(s -> s.length()));
3.9 summarizingInt/Double/Long
если мы правыРаздел 3.6 - Раздел 3.8Что делать с результатом операции? Может быть, мы делаем 5Stream
поток? Так что естьsummarizingInt
,summarizingDouble
,summarizingLong
три метода.
Извлекая атрибут элемента, эти три метода возвращают объект статистических данных атрибута элемента, соответствующийIntSummaryStatistics
,DoubleSummaryStatistics
,LongSummaryStatistics
. Мыservers
Длина элементов в статистике:
DoubleSummaryStatistics doubleSummaryStatistics = servers.stream.collect(Collectors.summarizingDouble(String::length));
// {count=5, sum=32.000000, min=5.000000, average=6.400000, max=8.000000}
System.out.println("doubleSummaryStatistics.toString() = " + doubleSummaryStatistics.toString());
результатDoubleSummaryStatistics
содержитВсего, Сумма, Мин., Макс., Среднеепять индикаторов.
3.10 mapping
Метод заключается в том, чтобы сначала использовать элементFunction
выполнить операцию повторной обработки, а затем использовать другуюCollector
индукция. Например, мы сначала удаляемservers
первая буква элементов вList
.
// [elordcn, omcat, etty, ndertow, esin]
servers.stream.collect(Collectors.mapping(s -> s.substring(1), Collectors.toList()));
несколько похожеStream
сделано первымmap
операция сноваcollect
:
servers.stream.map(s -> s.substring(1)).collect(Collectors.toList());
3.11 reducing
Этот метод очень полезен! Но если вы хотите понять это, вы должны понять его параметрыBinaryOperator<T>
. Это функциональный интерфейс, который дает две величины одного типа и возвращает результат того же типа, что и две величины.(T,T) -> T
. Две реализации даны по умолчаниюmaxBy
иminBy
, который сравнивает размер в соответствии с компаратором и возвращает максимальное или минимальное значение соответственно. Конечно, вы можете гибко настроить. потомreducing
Это легко понять. Сравнение между элементами основано на стратегии устранения одного. По ходу раунда количество элементовreduce
из. Так какая от этого польза? Чиновник Явы привел пример: посчитайте самого высокого человека в каждом городе.
Comparator<Person> byHeight = Comparator.comparing(Person::getHeight);
Map<String, Optional<Person>> tallestByCity = people.stream()
.collect(Collectors.groupingBy(Person::getCity, Collectors.reducing(BinaryOperator.maxBy(byHeight))));
В сочетании с примером, приведенным в начале, вы можете использоватьreducing
Попробуйте найти самую длинную строку.
Слой выше основан наHeight
Найдите высший атрибутPerson
, и если это свойство не имеет начального значения или данных, то результат, скорее всего, не будет получен, поэтому заданоOptional<Person>
. если мы дадимidentity
Сделайте эталонное значение, затем мы сначала проведем сравнение с этим эталонным значениемBinaryOperator
работать.
Например, мы даем человеку ростом более 2 метров какidentity
. Мы можем посчитать человека ростом не ниже 2 метров и самым высоким в каждом городе.Конечно, если в городе нет никого выше 2 метров, будет возвращено эталонное значение.identity
:
Comparator<Person> byHeight = Comparator.comparing(Person::getHeight);
Person identity= new Person();
identity.setHeight(2.);
identity.setName("identity");
Map<String, Person> collect = persons.stream()
.collect(Collectors.groupingBy(Person::getCity, Collectors.reducing(identity, BinaryOperator.maxBy(byHeight))));
В это время он обязательно вернетPerson
Ну, по крайней мере, это будет эталонное значениеidentity
Больше неOptional
.
В других случаях мы хотели быreducing
когдаPerson
Сначала округляется высота. Это требует от нас выполнения процесса сопоставления. определитьFunction<? super T, ? extends U> mapper
чтобы сделать эту работу. Затем приведенную выше логику можно изменить на:
Comparator<Person> byHeight = Comparator.comparing(Person::getHeight);
Person identity = new Person();
identity.setHeight(2.);
identity.setName("identity");
// 定义映射 处理 四舍五入
Function<Person, Person> mapper = ps -> {
Double height = ps.getHeight();
BigDecimal decimal = new BigDecimal(height);
Double d = decimal.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
ps.setHeight(d);
return ps;
};
Map<String, Person> collect = persons.stream()
.collect(Collectors.groupingBy(Person::getCity, Collectors.reducing(identity, mapper, BinaryOperator.maxBy(byHeight))));
4. Резюме
Сегодня мыJava 8серединаCollectors
подробно объяснил. если вы знакомы сCollectors
Операционный поток будет более удобным. Конечно вJava 8ПослеJava 9иJava 12серединаCollectors
Есть новые функции, и мы продолжим объяснять, когда будет время. быть в курсе!
关注公众号:Felordcn获取更多资讯