int val = integerList.stream().collect(
Collectors.reducing(0, a1 -> a1 * 5, (a1, a2) -> a1 + a2));
Приведенный выше код выполняет операцию сокращения. Преобразование потока целых чисел и функции агрегирования для возврата Integer . Я не мог понять приведенный ниже код и внутреннюю реализацию операции сокращения. Как Java может выполнять приведенную ниже функцию Stateful.? Спасибо!
java.util.stream.Collectors:reducing method
public static <T, U>
Collector<T, ?, U> reducing(U identity,
Function<? super T, ? extends U> mapper,
BinaryOperator<U> op) {
return new CollectorImpl<>(
boxSupplier(identity),
(a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); },
(a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
a -> a[0], CH_NOID);
}
Может быть, я немного уточню свой вопрос. Как приведенная выше реализация получает поток данных. Относится ли a[0],b[0] к потоку данных? Я считаю, что вышеизложенное обеспечивает функциональную реализацию для поставщика и аккумулятора. Я хотел понять, как работает процесс редукции через код.
Документация рассказывает о том, «что» можно сделать. Я ищу разъяснения о том, как это можно сделать.
Вы спрашиваете, как работает реализация?
Сейчас можно было бы сказать: «Посмотрите на код класса CollectorImpl», но на самом деле он лишь объединяет данные supplier, accumulator, combiner и finisher, а вся магия происходит в реализации ReferencePipeline. Кроме того, вам нужно будет более четко сказать, в чем заключается вопрос (также см. docs.oracle.com/javase/tutorial/collections/streams/… , если вы еще этого не сделали)
Несмотря на то, что код JVM хорошо написан, его часто трудно читать из-за уровня абстракции и сложности. Вы должны быть очень конкретными. «внутренняя реализация операции сокращения» четко не определена.
«Как Java может выполнять приведенную ниже функцию Stateful?» a и b — это массивы T[], в которых сохраняется промежуточное состояние
Да @Lino. Я спрашиваю о реализации
Спасибо @Marco13 и Эндрю Тобилико. ReferencedPipeline — хороший лидер. Вероятно, мне следует больше узнать о классе StreamSupport. Вот что я имел в виду Внутренняя реализация. Прежде чем я понял, получил голоса
Вы должны посмотреть на пакетная документация. Он показывает простой эквивалентный код для объяснения логики.




Функция принимает три аргумента:
Первый — это личность. При сокращении потока нужно с чего-то начинать (иначе, какой будет результат сокращения пустого списка?). Идентификатор — это объект, применяемый к первому аргументу первой операции редукции в цепочке.
Второй — картограф. reducing() — это обобщенная операция — вы можете свести элементы потока типа T к конечному результату типа U, поэтому вам нужно дать промежуточную операцию, которая предоставляет элемент типа U из элемента типа T. Если T == U и вы не хотите преобразования, вы можете указать здесь функцию идентификации
Третий аргумент — функция редукции — она применяется к элементам потока последовательно, начиная с личность.
Итак, в качестве примера:
Если вы хотите просто суммировать элементы потока Integer в целое число, вы можете использовать Collectors.reducing(0, x -> x, (x, y) -> x + y).
Если вы хотите суммировать длины String в потоке String, вы можете использовать Collectors.reducing(0, String::length, (x, y) -> x + y).
Если вы хотите получить максимум Double из строки Doubles, но не меньше Math.PI, вы можете использовать Collectors.reducing(Math.PI, x -> x, Math::max).
Кроме того, если вы хотите, чтобы ваша редукция сохраняла состояние, помните, что вы можете использовать в качестве редуктора ссылку на метод внутри объекта. Таким образом, объект можно использовать для сохранения состояния. Например, вот «уменьшитель налогов», который добавляет 1 «налог» к своему счету каждые 100 добавлений:
public class Taxer implements BinaryOperator<Integer> {
int counter = 0;
@Override
public Integer apply(Integer i1, Integer i2) {
counter++;
if (counter % 100 == 0) {
return i1 + i2 + 1;
} else {
return i1 + i2;
}
}
}
...
Taxer t = new Taxer();
...
.collect(Collectors.reducing(0, x -> x, t);
То же самое можно расширить, используя для реализации сложных случаев, таких как groupingBy:
Map<String, Integer> output = Stream.of("this", "word", "is", "the", "best")
.collect(Collectors.groupingBy(x-> x.substring(0, 1),
Collectors.reducing(0, x-> x.length(), (x, y)-> x + y)));
Здесь сначала входная строка группируется на основе символа, с которого она начинается, а затем суммируются длины
Отличный ответ, 3 балла помогли мне пройти. У меня возникла проблема с GroupBy с уменьшением. Я также добавил образец в ваш код. +1 за 3 балла ура
Спасибо за отличный ответ. Я понял уменьшающую операцию. (Чем просто зная).
Спасибо за вотум доверия, приятно знать, что это было действительно полезно :>
Вы ознакомились с документацией? Что там было непонятно?