Java 8是否支持作为第一类对象的功能?

SPI*_*984 8 java functional-programming

我今天读到了有关Java 8版本的内容.但我完全不了解Java 8中引用方法的概念.这是否意味着Java现在支持函数作为第一类对象?我已经看到,如何构造对函数的引用.但在我看来,他们提供的Converter对象功能非常有限.它现在可以在Java中使用:

  • 将函数作为参数传递给另一个函数?
  • 从另一个函数返回函数作为返回值?
  • 什么关闭?它们是否像功能语言一样完全实现,或者它们确实有一些限制?在我看来,有一些限制(你不能改变你在一个闭包中引用的变量的值,它必须被标记为final等等).

Sea*_*lly 8

有可能的。你怎么做呢?

首先构造一个“功能接口”(或使用提供的接口之一)。函数式接口是具有单一方法的接口。java.lang.Runnable 就是一个例子。

其次,编写一个以函数式接口作为参数的方法。

public void doAThing(Runnable r) {
    r.run();
}
Run Code Online (Sandbox Code Playgroud)

第三,编写具有正确签名的方法。

public class MyClass {
    public void runAThing() {
        System.out.println("I executed!");
    }
}
Run Code Online (Sandbox Code Playgroud)

第四,调用传入方法引用的函数。

MyClass mc = new MyClass();
doAThing(mc::runAThing);
Run Code Online (Sandbox Code Playgroud)

您会注意到您编写的所有类都没有显式实现Runnable. 这是由编译器为您处理的。

您可以使用 lamdba 表达式执行类似的操作:

doAThing(() -> System.out.println("I executed as a lamdba expression!"));
Run Code Online (Sandbox Code Playgroud)

要将函数作为另一个函数的值返回,只需返回 的实例Runnable


Mar*_*nik 8

第一类函数最重要的方面已经融入现有的Java类型系统中.没有引入真正的函数类型 ; 任何单方法接口都是它自己的"函数类型".因此,对于前两个问题,您可以自由地传递这些功能接口的实例.

语义有许多细微的变化,允许使用lambda语法/方法引用来实现任何这样的接口.您甚至可以使用高阶函数,例如compose返回泛型Function类型的函数,并将其传递给期望兼容的函数接口类型的方法.

您无法更改在闭包中引用的变量的值

这不是Java特有的限制.实际上,大多数FP语言都不支持任何类型的可变变量.请注意,不要求final在变量上使用关键字; 有效最终的概念照顾到了这一点.


ski*_*iwi 4

除了反射中已经存在的用法之外,方法并不是 Java 中的一流对象,来回答您的问题:

  1. 是的,可以传递,但是需要满足签名。

    • 对于 a ,void method()您可以使用 a Runnable,如下所示:
      Runnable method = this::method如果它位于同一个类中,则使用 运行实际方法method.run()
    • 但是,对于 adouble method()您需要使用 a DoubleSupplier,如下所示: DoubleSupplier method = this::method,然后将其用作double d = method.get()
    • 还有更多签名,您甚至可以使用功能接口定义自己的签名。
  2. 是的,这是可能的,但仅限于第 1 点中所示的特定签名。

  3. Lambda 的行为与匿名内部类完全相同,匿名内部类本身就是闭包,Java 自从引入匿名内部类以来就支持闭包。现在唯一添加的是语法更加漂亮。