1
List <Person> roster = new List<Person>();    
Integer totalAgeReduce = roster
  .stream()
  .map(Person::getAge)
  .reduce(
      0,
      (a, b) -> a + b);

Can anyone help me understand the above code snippet. My understanding is that the stream method will first iterate through the entire roster List and while it is iterating it will create a new List of the mapped objects with every person's age in it. Then it will finally call the reduce after the mapping is done (the reduce is only called at the end after mapping correct?). And in the reduce it starts of at 0, and in the first iteration of reduce on the newly mapped list a = 0 and b is equal to the first element in the List that was created from the mapping function. Then it will continue and add all the elements from the mapped list and return to you an integer with the sum of all the ages.

2
  • 1
    Essentially correct, but: 1) Is roster the same as the l variable? --- 2) stream() and map() do not "create" new lists. Logically you might think that way, but a better way to think of it is a pipeline. stream() sends the elements down a pipe. At a junction in the pipe, map strips the age out of the object and sends that down the pipe instead of the original object. reduce() then compresses all the ages into a single value, as defined by the supplied lambda. Commented Apr 1, 2016 at 23:07
  • 5
    Seems like a complicated way to write int totalAge = roster.stream().mapToInt(Person::getAge).sum(); Commented Apr 1, 2016 at 23:07

4 Answers 4

2

Each item in the stream will each be sent through all the steps one at a time. Here's some test code to help you see whats happening:

List<String> test = Arrays.asList("A","B");
System.out.println("END: " + test.stream()
        .map(s -> {System.out.println("1 " + s); return s; })
        .map(s -> {System.out.println("2 " + s); return s; })
        .reduce("", (acc, s) -> {System.out.println("3 " + s); return acc + s; })
);

Output

1 A
2 A
3 A
1 B
2 B
3 B
END: AB
Sign up to request clarification or add additional context in comments.

3 Comments

Are the return statements required in the body of the lambda expressions? Like in the reduce do you need return acc + s or can you just write acc + s?
You only need a return if you put in a scope {}. Otherwise it assumes the result of the single statement is the result. I wanted to add an extra command for println, so I had to indicate what value i wanted to be returned.
To be formally correct, the form param -> expression doesn’t need a return statement, but only a few statements (like method invocations) are also expressions. All other statements, like if, try or loops, need always the param -> { statement(s) } syntax and hence a return statement if a value is required. By the way, you can use Stream.of("A", "B") to create a two element stream…
2

TL;DR

It sums all the ages from the Person's within the List.


stream() : Creates a stream from the Collection (List)

map() : Will make a mapping from the received object to another object (here from Person to Integer (getAge returns an Integer))

reduce(0,(a, b) -> a + b) : reduce is a reduction (it reduces all the objects received into one (here the action is to add them all together, a big addition). It takes the identity (first value to begin with) as first argument and the following lambda expression (BinaryOperator<Integer> or BiFunction<Integer, Integer, Integer>) presents the logic to apply for the reduction.


Example

List<Person> persons = Arrays.asList(new Person("John", 20), 
                                     new Person("Mike", 40), 
                                     new Person("Wayne", 30));
Integer totalAgeReduce = roster.stream()
                               .map(Person::getAge)
                               .reduce(0,(a, b) -> a + b);
System.out.println(totalAgeReduce); // 90

Comments

0

The thing is

 (a, b) -> a + b);

is an accumulator, and if you look at it like a recursive function, it will be passing the result of the sum, for every element in the stream, as Andreas Point out is not a list, is a pipeline.

Just to point out lambda expressions is just passing an Argument which in fact is a function.

Comments

0

If you would use loops it would look like this:

List<Integer> ages = new ArrayList<>();
for (Person p : roster) {
    ages.add(p.getAge());
}

int sum = 0;
for (Integer age : ages) {
    sum += age;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.