整个列表上的 Java 8 流计算

标签 java java-8 stream java-stream

我看到 Let’s Get Lazy: Explore the Real Power of Streams youtube 上的视频 (venkat subramaniam)。 (大约 26-30 分钟)

在例子中,一个for循环:

List<Integer> numbers = Arrays.asList(1, 2, 3, 5, 4, 6, 7, 8, 9, 10);
int result = 0;
for(int e: values){
  if(e > 3 && e % 2 == 0){
    result = e * 2;
    break;
  }
}  

有8个“单元操作”

根据他的例子:

public class MainClass {
    public static void main(String[] args) {

        List<Integer> numbers = Arrays.asList(1, 2, 3, 5, 4, 6, 7, 8, 9, 10);

        System.out.println(
                numbers.stream()
                        .filter(e -> e > 3)
                        .filter(e -> e % 2 == 0)
                        .map(e -> e * 2)
                        .findFirst()
                        .orElse(0)
        );


    }
}

这段代码看起来有 21 个“单元操作”。

然后他推荐使用这段代码:

public class MainClass {
    public static void main(String[] args) {

        List<Integer> numbers = Arrays.asList(1, 2, 3, 5, 4, 6, 7, 8, 9, 10);

        System.out.println(
                numbers.stream()
                        .filter(MainClass::isGT3)
                        .filter(MainClass::isEven)
                        .map(MainClass::doubleIt)
                        .findFirst()
                        .orElse(0)
        );


    }

    private static int doubleIt(Integer e) {
        return e * 2;
    }

    private static boolean isEven(Integer e) {
        return e % 2 == 0;
    }

    private static boolean isGT3(Integer e) {
        return e > 3;
    }
}

我真的很想明白,这怎么能证明有8个单元运算而不是21个单元运算呢?

最佳答案

不不不,你误解了这个想法。这个想法是对流的惰性评估。两者都需要“8 次计算”(用他的话说),他试图说看起来需要 21 次。

这个

  numbers.stream()
                  .filter(MainClass::isGT3)
                  .filter(MainClass::isEven)
                  .map(MainClass::doubleIt)
                  .findFirst()
                  .orElse(0)

numbers.stream()
                .filter(e -> e > 3)
                .filter(e -> e % 2 == 0)
                .map(e -> e * 2)
                .findFirst()
                .orElse(0)

完全相同。唯一的区别是创建一个更具可读性的函数,仅此而已。 命令式代码:

List<Integer> numbers = Arrays.asList(1, 2, 3, 5, 4, 6, 7, 8, 9, 10);
int result = 0;
for(int e: values){
  if(e > 3 && e % 2 == 0){
    result = e * 2;
    break;
  }
}

和流中的代码,计算完全相同,因为它们是按需调用的,这意味着它不会过滤所有 > 3 和过滤所有 % 2 == 0,不,它结合了这些操作,然后在调用终端函数时应用它(如 findFirst())

如视频所示,如果您在函数之间放置一些印记,它将显示 8 个操作:

public class Main {

    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 5, 4, 6, 7, 8, 9, 10);

        System.out.println(processStream(numbers)); 
        System.out.println(getNumber(numbers));
        System.out.println(getNumberEfficient(numbers));
    }

    static Stream<Integer> processStream(List<Integer> numbers){
        return numbers.stream()
                .filter(e -> {
                    System.out.println("GT3: " + e);
                    return e > 3;
                })
                .filter(e -> {
                    System.out.println("is Even: " + e);
                    return e % 2 == 0;
                })
                .map(e -> {
                    System.out.println("times 2: " + e);
                    return e * 2;
                } );
    }

    static int getNumberEfficient(List<Integer> numbers){
        return numbers.stream()
                .filter(e -> {
                    System.out.println("GT3 and even: " + e);
                    return e > 3 && e % 2 == 0;
                })
                .map(e -> {
                    System.out.println("times 2: " + e);
                    return e * 2;
                } )
                .findFirst()
                .orElse(0);
    }

    static int getNumber(List<Integer> numbers){
        return numbers.stream()
                .filter(e -> {
                    System.out.println("GT3: " + e);
                    return e > 3;
                })
                .filter(e -> {
                    System.out.println("is Even: " + e);
                    return e % 2 == 0;
                })
                .map(e -> {
                    System.out.println("times 2: " + e);
                    return e * 2;
                } )
                .findFirst()
                .orElse(0);
    }
}

它将返回:

This is the pipeline, nothing was executed, because is laze

java.util.stream.ReferencePipeline$3@7ba4f24f

Thees are the 8 operations:

GT3: 1
GT3: 2
GT3: 3
GT3: 5
is Even: 5
GT3: 4
is Even: 4
times 2: 4
8

And this is a little optimization, instead of doing two filters, you can do only one, and reduce from 8 to 6:

GT3 and even: 1
GT3 and even: 2
GT3 and even: 3
GT3 and even: 5
GT3 and even: 4
times 2: 4
8

关于整个列表上的 Java 8 流计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57264756/

相关文章:

java - 更新 2D Java 数组中的对象

java - 使用泛型类时 lambda 使用者参数的类型未知

java - 如何在流式 json 中使用 jackson 的上下文?

python - 使用 Python 从 radio 流中读取 SHOUTcast/Icecast 元数据

java - 从 Java 桌面应用程序引用文档

Java ArrayList 空指针异常

java - 我已经编写了一个 Java servlet 代码来下载文件但出现错误

java - HashMap resize方法实现细节

对象上带有收集器的 Java 8 GroupingBy

java - "Your package name is not valid"Android 连接到 DEEZER