简体   繁体   English

流API map()和filter()

[英]Stream API map() and filter()

I am trying to learn the Stream API and i came across the below code: 我正在尝试学习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());
    }
}

It gives a 它给了一个

symbol "average()"not found error. 符号“average()”未找到错误。

But when I change the sysout with the below it runs fine as expected 但是,当我用下面的更改sysout时,它按预期运行正常

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

Can someone please explain the difference here? 有人可以解释这里的区别吗?

A Stream<T> has no average() method, since the element type T can be any reference type, which doesn't necessarily have a meaning for calculation of the average of the Stream elements. Stream<T>没有average()方法,因为元素类型T可以是任何引用类型,其不一定具有计算Stream元素的平均值的含义。

On the other hand, an IntStream has an average() method, since it has int elements, for which the average operation is well defined. 另一方面, IntStream有一个average()方法,因为它有int元素,为其定义了平均操作。

Therefore you must convert a Stream<Integer> to an IntStream (via mapToInt() ) in order to call average() . 因此,您必须将Stream<Integer>转换为IntStream (通过mapToInt() )才能调用average()

To explain it a bit more in detail: 更详细地解释一下:

This is giving you a List of Integer (the arguments are boxed from int to Integer ): 这给你一个Integer List (参数从int加到Integer ):

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

The following statement is converting your List<Integer> into a Stream<Integer> 以下语句将List<Integer>转换为Stream<Integer>

a.stream()

Now filtering still preserves the type Stream<Integer> , and Stream doesn't provide a method called average() (as it can consist of any generic type). 现在,过滤仍保留Stream<Integer>类型, Stream不提供名为average()的方法(因为它可以包含任何泛型类型)。

Calling mapToInt(i -> i) converts your Stream<Integer> into an IntStream , which does have a method called average() . 调用mapToInt(i -> i)Stream<Integer>转换为IntStream ,它有一个名为average()的方法。 Note that i -> i is a ToIntFunction<Integer> , which converts an Integer back to an int due to auto-unboxing. 请注意, i -> iToIntFunction<Integer> ,它会因自动取消装箱而将Integer转换回int

Another way to fix that would be 解决这个问题的另一种方法是

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

Expressing calculations as chains is convenient, but sometimes it hides type information that might be useful to understanding what's going on. 将计算表示为链是很方便的,但有时它会隐藏可能有助于理解正在发生的事情的类型信息。 Try rewriting 尝试重写

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

where every result has an explicit type (your IDE should help you.) Then you get: 每个结果都有一个显式类型(你的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();

When you write it this way, you'll see that you're trying to invoke a nonexistent method on Stream<Integer> . 当您以这种方式编写它时,您将看到您尝试在Stream<Integer>上调用不存在的方法。 You want an IntStream , which does have an average() method. 你想要一个IntStream ,它有一个average()方法。 So you can rewrite as: 所以你可以重写为:

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();

and everything is good. 一切都很好。 Then you can roll it back up with chaining and implicit lambdas: 然后你可以用链接和隐式lambda来回滚它:

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

The lesson here is: when you're confused, unroll complex expressions into simpler ones with manifest types. 这里的教训是:当您感到困惑时,将复杂的表达式展开为具有清单类型的简单表达式。 Often, this helps you spot the problem immediately; 通常,这可以帮助您立即发现问题; if not, it generally results in a more informative compiler error. 如果不是,它通常会导致更具信息性的编译器错误。

(If you use IntelliJ, you can use the "extract variable" refactor to pull a subexpression into a local variable with its inferred type.) (如果使用IntelliJ,则可以使用“提取变量”重构将子表达式拉入具有推断类型的局部变量。)

Arrays.asList(2,3,4).stream() would given you Stream<Integer> which is of type Stream and it does not have any average() method, hence the error. Arrays.asList(2,3,4).stream()会给你Stream<Integer> ,它是Stream类型,它没有任何average()方法,因此错误。

Arrays.asList(2,3,4).mapToInt() would return IntStream which is one of the four primitive specialized classes provided by Stream API and it has average() method, hence it works. Arrays.asList(2,3,4).mapToInt()将返回IntStream,它是Stream API提供的四个原始专用类之一,它具有average()方法,因此它可以工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM