Let the world have no difficult to learn Java
Like, follow, favorites
1, the preface
-
What is reduce? Simply speaking, I think reduce is a normalized iterative operation. Take a stream and combine them into a simple result by repeatedly applying the operations.
-
Collect returns List<T>, Set<T>, Map<T>… Reduce usually only returns T (but T is generic, you can actually return any type including List in the class).
-
This article mainly introduces reduce () with three parameters, parallel, non-thread-safe, and combiner.
Optional<T> reduce(BinaryOperator<T> accumulator);
T reduce(T identity,BinaryOperator<T> accumulator);
<U> U reduce(U identity,BiFunction<U,? super T,U> accumulator,BinaryOperator<U> combiner);
Copy the code
2. Test the cat
- Reduce of one parameter
- Sum, min, Max and other bottom layers are realized by Reduce.
/ * * * *@param: accumulator
* @return: Optional
*/
Optional<T> reduce(BinaryOperator<T> accumulator);
Copy the code
- The BinaryOperator
can be regarded as a special case of BiFunction
,t,t>
.
public class Main {
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1.2.3.4.5);
list.stream().reduce(
new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
returninteger + integer2; }}));//===== is equivalent to =====
System.out.println(IntStream.range(1.100).reduce((v1, v2) -> v1 + v2).orElse(0));
//===== is equivalent to =====
System.out.println(IntStream.range(1.100).reduce(Integer::sum).orElse(0));
}
}
integer=1===integer2=2
integer=3===integer2=3
integer=6===integer2=4
integer=10===integer2=5
Copy the code
3. Flex your muscles
- A two-parameter reduce is actually one more initial value than one parameter. That is, the first parameter in the first iteration of Reduce is specified.
public class Main {
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1.2.3.4.5);
// The initial value is 100
list.stream().reduce(
100.new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
System.out.println("integer="+integer+"===integer2="+integer2);
returninteger + integer2; }})); }}// The initial value is 100, not 1. One more iteration than reduce with no initial value.
integer=100===integer2=1
integer=101===integer2=2
integer=103===integer2=3
integer=106===integer2=4
integer=110===integer2=5
Copy the code
Spread your wings and soar
- The first two are all underdogs, and the three-parameter Reduce is the big BOSS.
- First of all, the third parameter is useless for non-parallel flow. If there is only one element in the stream, even if parallel is specified, parallel will not run.
- When using three-parameter reduce, it is important to be thread-safe.
<U> U reduce(U identity,BiFunction<U,? super T,U> accumulator,BinaryOperator<U> combiner);
Copy the code
- BiFunction, the first parameter T, the second parameter U, returns R
=====> (T t,U u)-> (R)r
Copy the code
@FunctionalInterface
public interface BiFunction<T.U.R> {
R apply(T t, U u);
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return(T t, U u) -> after.apply(apply(t, u)); }}Copy the code
- Let’s see a demo (take a few minutes to think about it, maybe you’ll understand it completely).
public static void main(String[] args) {
ArrayList<Integer> accResult = Stream.of(1.3.5.7)
.reduce(new ArrayList<>(),
new BiFunction<ArrayList<Integer>, Integer, ArrayList<Integer>>() {
@Override
public ArrayList<Integer> apply(ArrayList<Integer> integers, Integer item) {
System.out.println("before add: " + integers);
System.out.println("item= " + item);
integers.add(item);
System.out.println("after add : " + integers);
System.out.println("In BiFunction");
returnintegers; }},new BinaryOperator<ArrayList<Integer>>() {
@Override
public ArrayList<Integer> apply(ArrayList
integers, ArrayList
integers2)
{
integers.addAll(integers2);
System.out.println("integers: " + integers);
System.out.println("integers2: " + integers2);
System.out.println("In BinaryOperator");
returnintegers; }}); System.out.println("accResult: " + accResult);
}
Copy the code
- The third parameter is not printed at all? Why do you need a third parameter? Don’t worry
public static void main(String[] args) {
ArrayList<Integer> accResult = Stream.of(1.3.5.7).parallel()
.reduce(new ArrayList<>(),
new BiFunction<ArrayList<Integer>, Integer, ArrayList<Integer>>() {
@Override
public ArrayList<Integer> apply(ArrayList<Integer> integers, Integer item) {
integers.add(item);
returnintegers; }},new BinaryOperator<ArrayList<Integer>>() {
@Override
public ArrayList<Integer> apply(ArrayList
integers, ArrayList
integers2)
{
integers.addAll(integers2);
System.out.println("thread name="+Thread.currentThread().getName()+" ==== integers=" + integers);
System.out.println("integers2: " + integers2);
System.out.println("In BinaryOperator");
returnintegers; }});// Prints different results almost every time
System.out.println("accResult: " + accResult);
}
Copy the code
- Parallel, print results almost different every time, and a bunch of null. The data is also incomplete, my 1,3,5,7 are incomplete. Sometimes there are exceptions.
5. Reduce in parallel flow
- Thread safety issues arise with concurrent flow. ArrayList, for example, is a non-thread-safe class, and many operations can lead to unexpected results.
5.1 Parallel Reduce for basic data types
public static void main(String[] args) {
System.out.println(
Stream.of(1.2.3.4).parallel().reduce(5.new BiFunction<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
returninteger + integer2; }},new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
returninteger + integer2; }})); }Copy the code
- Accumulator =stream, and the number of combiner is 1 less than accumulator.
5.2. If the first argument is an object such as ArrayList rather than a primitive data type or String, the result may be quite different from what we expect.
-
Print results, thread names will probably not be inconsistent, and ArrayList is not thread-safe. (if the Collections. SynchronizedList under (a) the packing element is not less).
-
Focus on the System. The out. Println (acc = = item); . The second parameter of each Accumulator is the same as the ArrayList in the first parameter.
-
If the List < Integer > a into Collections. SynchronizedList (a), then the order is not necessarily consistent, but the elements must be full.
// Outline of the diagram
6, summary
- Three overloaded functions of reduce are briefly introduced, and reduce with three parameters is emphasized.
- Accumulator (the third parameter) is not used for non-parallel flow. The number of accumulator in parallel flow is the same as that of stream elements, and the number of combiners is one less than that of stream elements.
- The first parameter of Combiner is ArrayList and other object types and the differences between the basic types are explained.