Java 8 Lambdas:将流映射到 Integer 类型,然后调用 sum() 将无法编译

2022-09-03 01:28:44

我正在玩Java8 lambda表达式。作为一个例子,我试图总结一个列表中包含的年龄:

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;
    }
}

当我尝试使用以下java编译器编译此代码段时:

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)

我收到以下编译错误:

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

但是,如果我将 getAge() 方法的返回值从 Integer 更改为 int,我会得到预期的结果。但有时不可能或不希望动态更改签名。当 getAge() 返回 Integer 类型时,有没有办法使它工作?

提前致谢,丹尼尔


答案 1

我认为他们正在改变方法

IntStream map(ToIntFunction<? super T> mapper)

IntStream mapToInt(ToIntFunction<? super T> mapper)

然后你的

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

将始终有效,无论是返回还是 .getAge()intInteger

请参阅此主题:http://mail.openjdk.java.net/pipermail/lambda-libs-spec-experts/2013-March/001480.html

顺便说一句,您可以将您的问题发布到lambda-dev邮件列表,他们希望听到现实世界的经验。


答案 2

它们没有改变方法,它们都可用,因为map()是返回Stream的通用方法,并且它们已将int,long,double Stream分离为单独的方法,例如mapToInt(),mapToLong()和mapToDouble()。

是的,您可以使用 reduce() 方法

reduce(T 恒等式、二进制操作器< T > 累加器)

使用关联累积函数对此流的元素执行缩减,并返回描述缩减值(如果有)的 Optional。

reduce() 的工作原理:假设我们有 int 数组流,我们应用 reduce 函数

减少(0, (l, r) -> l + r)

在整数列表(如 1、2、3、4 和 5)中,将种子 0 添加到 1,并将结果 (1) 存储为累积值,然后,除了用作流中的下一个数字 (1+2) 之外,该值还用作左侧值。结果 (3) 存储为累积值,并在下一次加法 (3+3) 中使用。结果(6)被存储并在下一个加法(6 + 4)中使用,结果用于最终加法(10 + 5),产生最终结果15。

所以你的例子看起来像这样:

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;
    }
}