【问题标题】:Java 8 Lambdas and Streams... not a "how" , but a "why"? [duplicate]Java 8 Lambdas 和 Streams...不是“如何”,而是“为什么”? [复制]
【发布时间】:2017-09-10 19:27:18
【问题描述】:

我的问题涉及 Lambdas 和 Streams。有几件事我无法解决。从 lambda 开始,以 Predicate 为例。

请注意,在下面的代码中,我既没有导入“java.util.function.Predicate”,也没有在类声明中实现 Predicate 接口。然而,Lambda 工作得很好。这是为什么呢?

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

    public static void main(String[] args) {
        // passing the numbers List and different Lambdas to the intermediate
        // function.
        System.out.println();
        printVals(numbers, x -> x > 6); // all values greater than 6
        System.out.println();
        printVals(numbers, x -> x % 2 == 0); // all even values
        System.out.println();
        printVals(numbers, x -> x < 8); // ll values less than 8
        System.out.println();
        printVals(numbers, x -> x % 2 == 1); // all odd values
    }

    //intermediate Predicate function
    public static void printVals(List<Integer> val, Predicate<Integer>
            condition) {
        for (Integer v : val) {
            if (condition.test(v)) // if true, print v
                System.out.print(v + " ");
        }
    }
}

注意我必须如何使用一个“中间函数”,该函数利用 Predicate 函数接口的“test()”方法。 但是,如果我决定在使用流时做类似的事情,我又不必导入 java.util.function.Predicate 或 java.util.Stream,也不必在类声明中实现 Predicate 接口。此外,我可以在流中使用 Predicate Lambda,甚至无需创建中间函数!这是为什么呢?

例如:

// a predicate lambda that prints the first value greater than 3, in this case 5
public class Sample1 {
    public static void main(String[] args) {
        List<Integer> values = Arrays.asList(1, 2, 3, 5, 4, 6, 7, 8, 9, 10);

        System.out.println(
                values.stream()
                        .filter(e -> e > 3)
                        .findFirst()
        );
    }
}

所以,我对 Lambda 和流的规则的“为什么”感到非常困惑,但对“如何”却不太了解。

【问题讨论】:

  • nor do I implement the Predicate interface in the class declaration - 但你确实有。 lambda 您对此接口的实现。
  • 你有没有试过研究这个?几乎每个教程都涵盖了它,这里也有很多关于 SO 的答案。
  • 如果您从不在源代码的任何地方使用谓词符号,为什么需要导入它?从 Java 0 开始就是这种情况。例如,System.out.println(Arrays.asList(1, 2, 3)) 使用 PrintStream 和 List,不需要导入 PrintStream 或 List。导入只需要能够使用简单名称 Foo 而不是完全限定名称 com.mycompany.Foo
  • FacePalm!是的,如果我使用完全限定名称,为什么要导入。但是我从不使用完全限定的名称吗?我只是创建了一个中间函数,并调用了 test() ...对于流示例,我只是使用了“谓词样式” lambda .....我确定我在这里错过了所有树木的森林,所以请耐心等待我:)
  • 阅读 Jose 的回答:它比我做的更好地表达了我的意思。关于您的问题请注意,在以下代码中,我既没有导入“java.util.function.Predicate”,也没有在类声明中实现 Predicate 接口。然而,Lambda 工作得很好。,不,这是不正确的。如果不导入 java.util.function.Predicate、java.util.Arrays 和 java.util.List,此代码将无法编译。 Sample1 需要导入 java.util.Arrays,因为您在代码中使用了 Arrays。它不需要导入 java.util.function.Predicate 因为符号 Predicate 永远不会在代码中。

标签: java lambda java-8 java-stream


【解决方案1】:

导入主要是为了让你不必写一个类的完整包名。因此,在这种情况下,如果您在代码中的某处使用 Predicate 一词,则需要导入 Predicate。例如,如果您确实必须使用单词 Predicate 而是写出完整的包名称 java.util.function.Predicate,那么您就不需要包含导入。

Import 不用于为您的代码提供该类的公共 API。所以你不需要导入Predicate 来为Predicate 创建一个lambda。编译器已经知道 filter 方法引用了哪个 Predicate 类。

【讨论】:

    【解决方案2】:

    问题是Predicate 给你,而不是编译器。如果我们只写这个:

    x -> x > 6
    

    这是Predicate,对吧?但为什么不是Function 呢?

    Function<Integer, Boolean> func = x -> x > 6;
    

    或任何可能适合此处的其他类型。

    这也与 lambda 表达式本身不是内置的事实有关(逻辑上类似于 enum - 它只是一些复杂的糖)并且因为您没有直接使用Predicate 在这里,编译器将其推断为 Predicate

    【讨论】:

      【解决方案3】:

      要搜索的关键字是功能界面

      每个只需要你实现一个方法的接口(默认方法实现被认为已经实现)都是一个函数式接口,可以用 Java 8 中的 lambda 表示法或相应的方法引用代替。

      Java 8 带有一组用于常见任务的预定义功能接口(@98​​7654321@、FunctionPredicateConsumer 等),流 API 使用它们。

      例如,filter() 方法采用 Predicate,它是一个函数式接口。因此,您可以将其编写为 lambda 表达式或作为对采用单个参数并返回布尔值的方法的方法引用。类型参数 T 可以从流中上一步的返回值的类型推断出来。

      其余部分的工作方式与 Java 中的所有其他地方一样:如果您没有在类中显式使用类的符号名称,则不需要导入它,即使您的类调用了接受并返回它的方法其他类。

      将函数式接口的实现想象成类似于匿名类,只是更轻量级且语法更短。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-06
        • 2015-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多