有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

列出为什么lambda不声明在其中使用的变量就可以工作?(爪哇)

下面是一个代码示例,它似乎正在工作,但我不明白为什么:

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

Java如何知道变量元素意味着列表元素?尽管javadoc说参数必须是一元运算符,为什么replaceAll方法仍然有效

default void replaceAll(UnaryOperator<E> operator)

我试图通过一步一步地调试来理解它,但没有多大帮助。谢谢你的回答


共 (2) 个答案

  1. # 1 楼答案

    How does Java know that the variable element means an element of list?

    它不在乎它是列表的元素,但是因为List接口被声明为List<E>,其中E是元素的类型,当replaceAll方法声明它需要UnaryOperator<E>时,Java编译器可以推断您必须向它传递UnaryOperator<Integer>

    the javadoc says the argument has to be a unary operator

    由于编译器知道您确实需要一个UnaryOperator<Integer>,并且UnaryOperator只有一个抽象方法(称为apply),因此它会尝试查看您提供的lambda是否与该方法的签名匹配:

    • 编译器需要一个UnaryOperator<Integer>

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

    • 编译器查看lambda,它接受一个参数element,并发现如果它推断Integer element,那么lambda表达式的值也将是一个匹配的Integer,因此它将lambda转换为与以下代码等价的值:

      new UnaryOperator<Integer>() {
        @Override
        Integer apply(Integer element) {
          return element % operator;
        }
      }
      
  2. # 2 楼答案

    UnaryOperator是一个functional interface,因此,“可以使用lambda表达式创建函数接口的实例”

    How does Java know that the variable element means an element of list?

    它不知道。它只知道你传递了一个lambda,它接受一个输入element并返回一个结果,并且从泛型类型参数推断出类型为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()));
        }
    }