流API map()和filter()

问题描述 投票:3回答:4

我正在尝试学习Stream API,我遇到了以下代码:

public class Test{
    public static void main (String[] args)
    {    
        List <Integer> a = Arrays.asList(2,3,4);
        System.out.println(a.stream().filter(i -> i < 10).average());
    }
}

它给了一个

符号“average()”未找到错误。

但是,当我用下面的更改sysout时,它按预期运行正常

System.out.println(a.stream().filter(i -> i < 10).mapToInt(i -> i).average());

有人可以解释这里的区别吗?

java lambda java-8 java-stream
4个回答
9
投票

Stream<T>没有average()方法,因为元素类型T可以是任何参考类型,其不一定具有计算Stream元素的平均值的含义。

另一方面,IntStream有一个average()方法,因为它有int元素,平均操作很好地定义。

因此,您必须将Stream<Integer>转换为IntStream(通过mapToInt())才能调用average()


3
投票

更详细地解释一下:

这给你一个ListInteger(参数从int盒装到Integer):

List <Integer> a = Arrays.asList(2,3,4);

以下声明将您的List<Integer>转换为Stream<Integer>

a.stream()

现在过滤仍保留Stream<Integer>类型,而Stream不提供名为average()的方法(因为它可以包含任何泛型类型)。

调用mapToInt(i -> i)将你的Stream<Integer>转换为IntStream,它的确有一种叫做average()的方法。请注意,i -> i是一个ToIntFunction<Integer>,由于自动拆箱,它将Integer转换回int

解决这个问题的另一种方法是

System.out.println(IntStream.of(2,3,4).filter(i -> i < 10).average());

2
投票

将计算表示为链是很方便的,但有时它会隐藏可能有助于理解正在发生的事情的类型信息。尝试重写

List <Integer> a = Arrays.asList(2,3,4);
System.out.println(a.stream().filter(i -> i < 10).average());

每个结果都有一个显式类型(你的IDE应该帮助你。)然后你得到:

List <Integer> a = Arrays.asList(2,3,4);
Stream<Integer> s1 = a.stream();
Stream<Integer> s2 = s1.filter((Integer i) -> i < 10);
double average = s2.average();

当你用这种方式编写它时,你会发现你正试图在Stream<Integer>上调用一个不存在的方法。你想要一个IntStream,它有一个average()方法。所以你可以重写为:

List<Integer> a = Arrays.asList(2,3,4);
Stream<Integer> s1 = a.stream();
IntStream s2 = s1.mapToInt((Integer i) -> i);
IntStream s3 = s2.filter((Integer i) -> i < 10);
double average = s3.average();

一切都很好。然后你可以用链接和隐式lambda来回滚它:

double average = a.stream()
                  .mapToInt(i -> i)
                  .filter(i -> i<10)
                  .average();

这里的教训是:当您感到困惑时,将复杂的表达式展开为具有清单类型的简单表达式。通常,这可以帮助您立即发现问题;如果不是,它通常会导致更具信息性的编译器错误。

(如果使用IntelliJ,则可以使用“提取变量”重构将子表达式拉入具有推断类型的局部变量。)


1
投票

Arrays.asList(2,3,4).stream()会给你Stream<Integer>,它是Stream类型,它没有任何average()方法,因此错误。

Arrays.asList(2,3,4).mapToInt()将返回IntStream,这是Stream API提供的四个原始专用类之一,它有average()方法,因此它可以工作。

© www.soinside.com 2019 - 2024. All rights reserved.