Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Lambdas: Mapping a Stream to type Integer and then calling sum() won't compile

I was playing around with Java8 lambda expressions. As an example I then tried to sum up the ages persons contained in a list:

import java.util.Arrays;
import java.util.List;

public class Person {
    public static void main(String[] args) {
        List<Person> persons = Arrays.asList(new Person("FooBar", 12), new Person("BarFoo", 16));
        Integer sumOfAges = persons.stream().map(Person::getAge).sum();
        System.out.println("summedUpAges: " + sumOfAges);
    }

    private final String name;
    private final Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }
}

When I try to compile this snippet with the following java compiler:

openjdk version "1.8.0-ea"
OpenJDK Runtime Environment (build 1.8.0-ea-lambda-night
OpenJDK 64-Bit Server VM (build 25.0-b21, mixed mode)

I get the following compile error:

java: cannot find symbol
  symbol:   method sum()
  location: interface java.util.stream.Stream<java.lang.Integer>

But if I change the return value of the getAge() method from Integer to int, I get the expected result. But sometimes it is not possible or desired to change signatures on the fly. Is there any way to make this working when getAge() returns a Integer type?

Thanks in advance

like image 584
Daniel K. Avatar asked Mar 21 '13 19:03

Daniel K.


People also ask

Which stream operations are needed to get sum of all even numbers from stream of integer values?

Using Stream.collect() The second method for calculating the sum of a list of integers is by using the collect() terminal operation: List<Integer> integers = Arrays. asList(1, 2, 3, 4, 5); Integer sum = integers. stream() .

What are the two conditions required for using a lambda function in a stream?

In order to match a lambda to a single method interface, also called a "functional interface", several conditions need to be met: The functional interface has to have exactly one unimplemented method, and that method (naturally) has to be abstract.

Does Java 8 streams support functional programming?

Operations and example of using Java 8 streamsjoining(“ ”)) utilizes functional programming style by applying Java 8 streams functions to perform an operation on the elements of a list by joining them with space “ “ between the words and this was an example of how streams are used.


2 Answers

I think they are changing the method

IntStream map(ToIntFunction<? super T> mapper)

to

IntStream mapToInt(ToIntFunction<? super T> mapper)

then your

persons.stream().mapToInt(Person::getAge).sum()

will always work, whether getAge() returns int or Integer.

See this thread: http://mail.openjdk.java.net/pipermail/lambda-libs-spec-experts/2013-March/001480.html

BTW you can post your questions to lambda-dev mailing list, they'd like to hear real world experiences.

like image 136
ZhongYu Avatar answered Nov 08 '22 05:11

ZhongYu


They are not changing the methods, both of them are available where as map() is a generalized method that returns Stream, and they have separated the int, long, double Stream into separate method such as mapToInt(), mapToLong() and mapToDouble().

Yes, you can use reduce() method

reduce(T identity, BinaryOperator< T > accumulator)

Performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any.

How reduce() works: suppose we have stream of int array and we apply the reduce function

reduce(0, (l, r) -> l + r)

In a list of integers such as 1, 2, 3, 4, and 5, the seed 0 is added to 1 and the result (1) is stored as the accumulated value, which then serves as the left-hand value in addition to serving as the next number in the stream (1+2). The result (3) is stored as the accumulated value and used in the next addition (3+3). The result (6) is stored and used in the next addition (6+4), and the result is used in the final addition (10+5), yielding the final result 15.

So you example would look like:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class Person {

    public static void main(String[] args) {
        List<Person> persons = Arrays.asList(new Person("FooBar", 12), new Person("BarFoo", 16));
        Stream<Integer> stream = persons.stream().map(x -> x.getAge());
        int sum = stream.reduce(0, (l, r) -> l + r);
        System.out.println(sum);

    }

    private final String name;
    private final Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }
}
like image 25
pardeep131085 Avatar answered Nov 08 '22 06:11

pardeep131085