【问题标题】:Why do lambdas work without declaration of the variable you're using in it? (Java)为什么 lambdas 可以在没有声明您在其中使用的变量的情况下工作? (爪哇)
【发布时间】:2021-03-30 16:29:59
【问题描述】:

这是一个似乎可以工作但我不明白为什么的代码示例:

public static void replaceElements(List<Integer> list, int operator) {
    list.replaceAll(element -> element % operator);
}

Java 是如何知道变量 element 是指 list 的一个元素?为什么尽管 javadoc 说参数必须是一元运算符,但 replaceAll 方法仍然有效?:

default void replaceAll(UnaryOperator<E> operator)

我试图通过逐步调试来理解它,但它并没有太大帮助。感谢您的任何回答!

【问题讨论】:

    标签: java list generics lambda


    【解决方案1】:

    Java怎么知道变量元素是指list的一个元素?

    它并不关心它是否是列表的元素,但是因为List 接口被声明为List&lt;E&gt;,其中E 是元素的类型,当replaceAll 方法声明它接受 UnaryOperator&lt;E&gt;,Java 编译器可以推断您必须将 UnaryOperator&lt;Integer&gt; 传递给它。

    javadoc 说参数必须是一元运算符

    由于编译器知道您确实需要UnaryOperator&lt;Integer&gt;,而UnaryOperator只有一个抽象方法(称为apply),它会尝试查看您提供的lambda是否匹配该方法的签名:

    • 编译器需要UnaryOperator&lt;Integer&gt;

    • 编译器尝试匹配Integer apply(Integer)(一种将Integer作为参数并返回Integer的方法)

    • 编译器查看你的 lambda,它接受一个参数 element,并看到如果它推断出 Integer element,那么 lambda 表达式的值也将是一个匹配的 Integer,因此它转换你的lambda 转换成这段代码的等价物:

      new UnaryOperator<Integer>() {
        @Override
        Integer apply(Integer element) {
          return element % operator;
        }
      }
      

    【讨论】:

    • 非常感谢!这有很大帮助,尤其是最后一段等效代码! :)
    【解决方案2】:

    UnaryOperatorfunctional interface,因此“可以使用 lambda 表达式创建功能接口的实例”

    Java如何知道变量元素是指list的一个元素?

    它没有。它所知道的只是你传递了一个接受输入element 并返回结果的lambda,并且类型是从泛型类型参数推断为Integer。是 List 本身迭代其元素并将此 lambda 应用于每个元素:

    default void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final ListIterator<E> li = this.listIterator();
        while (li.hasNext()) {
            li.set(operator.apply(li.next()));
        }
    }
    

    【讨论】:

    • 谢谢!这很有帮助!你能在reddit上给予类似的奖励或类似的东西吗? :'D
    猜你喜欢
    • 1970-01-01
    • 2016-09-18
    • 2014-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-27
    • 2016-12-10
    • 2019-02-07
    相关资源
    最近更新 更多