Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6c3e4c7

Browse files
committed
Fixed MapUsingReduce
Contract of Stream.reduce method requires that accumulator function does not mutate its arguments. Previous implementation of MapUsingReduce.map method was using accumulator and combiner functions that were mutating list passed as argument. Mutating parameters in accumulator and combiner functions results in incorrect behaviour when parallel stream is processed. New implementation of MapUsingReduce.map copies argument lists in accumulator and combiner functions. This is very inefficient. Stream.collect method could be used to implement more efficient mutable reduction, but exercise 1 of chapter 3 asks to use reduce method explicitly. Unit test MapUsingReduceTest was updated to check functionality of MapUsingReduce.map with parallel streams.
1 parent 2177286 commit 6c3e4c7

File tree

3 files changed

+24
-11
lines changed

3 files changed

+24
-11
lines changed

src/main/java/com/insightfullogic/java8/answers/chapter3/MapUsingReduce.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,19 @@ public class MapUsingReduce {
1212

1313
public static <I, O> List<O> map(Stream<I> stream, Function<I, O> mapper) {
1414
return stream.reduce(new ArrayList<O>(), (acc, x) -> {
15-
acc.add(mapper.apply(x));
16-
return acc;
15+
// We are copying data from acc to new list instance. It is very inefficient,
16+
// but contract of Stream.reduce method requires that accumulator function does
17+
// not mutate its arguments.
18+
// Stream.collect method could be used to implement more efficient mutable reduction,
19+
// but this exercise asks to use reduce method.
20+
List<O> newAcc = new ArrayList<>(acc);
21+
newAcc.add(mapper.apply(x));
22+
return newAcc;
1723
}, (List<O> left, List<O> right) -> {
18-
left.addAll(right);
19-
return left;
24+
// We are copying left to new list to avoid mutating it.
25+
List<O> newLeft = new ArrayList<>(left);
26+
newLeft.addAll(right);
27+
return newLeft;
2028
});
2129
}
2230

src/test/java/com/insightfullogic/java8/answers/chapter3/MapUsingReduceTest.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package com.insightfullogic.java8.answers.chapter3;
22

3-
import com.insightfullogic.java8.answers.chapter3.MapUsingReduce;
4-
import org.junit.Test;
3+
import static java.util.Arrays.asList;
4+
import static org.junit.Assert.assertEquals;
55

66
import java.util.Collections;
77
import java.util.List;
88
import java.util.function.Function;
99

10-
import static java.util.Arrays.asList;
11-
import static org.junit.Assert.assertEquals;
10+
import org.junit.Test;
1211

1312
public class MapUsingReduceTest {
1413

@@ -30,6 +29,9 @@ public void incrementingNumbers() {
3029
private <I, O> void assertMapped(Function<I, O> mapper, List<I> input, List<O> expectedOutput) {
3130
List<O> output = MapUsingReduce.map(input.stream(), mapper);
3231
assertEquals(expectedOutput, output);
32+
33+
List<O> parallelOutput = MapUsingReduce.map(input.parallelStream(), mapper);
34+
assertEquals(expectedOutput, parallelOutput);
3335
}
3436

3537
}

src/test/java/com/insightfullogic/java8/exercises/chapter3/MapUsingReduceTest.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package com.insightfullogic.java8.exercises.chapter3;
22

3-
import org.junit.Test;
3+
import static java.util.Arrays.asList;
4+
import static org.junit.Assert.assertEquals;
45

56
import java.util.Collections;
67
import java.util.List;
78
import java.util.function.Function;
89

9-
import static java.util.Arrays.asList;
10-
import static org.junit.Assert.assertEquals;
10+
import org.junit.Test;
1111

1212
public class MapUsingReduceTest {
1313

@@ -29,6 +29,9 @@ public void incrementingNumbers() {
2929
private <I, O> void assertMapped(Function<I, O> mapper, List<I> input, List<O> expectedOutput) {
3030
List<O> output = MapUsingReduce.map(input.stream(), mapper);
3131
assertEquals(expectedOutput, output);
32+
33+
List<O> parallelOutput = MapUsingReduce.map(input.parallelStream(), mapper);
34+
assertEquals(expectedOutput, parallelOutput);
3235
}
3336

3437
}

0 commit comments

Comments
 (0)