12

I've read today about the Java 8 release. But I don't understand fully the concept of reference methods in Java 8. Does this mean that Java now has the support of functions as first class objects? I have seen, how to construct a reference to function. But it seems to me, that the Converter object they provide has quite limited functionality. Is it now possible in Java:

  • to pass the function as the argument to another function?
  • to return the function as the return value from another function?
  • and what about closures? Are they implemented fully like in functional languages, or they do have some limitations? It seems to me that there are some limitations (you cannot change the value of the variable you reference in a closure, it must be marked as final and etc).
Lyubomyr Shaydariv
  • 20,327
  • 12
  • 64
  • 105
SPIRiT_1984
  • 2,717
  • 3
  • 29
  • 46

4 Answers4

11

The most important aspects of first-class functions have been blended into the existing Java type system. No true function type has been introduced; any single-method interface is its own "function type". So, as for your first two questions, you can freely pass around instances of such functional interfaces.

There are many subtle changes to the semantics, which allow one to use lambda syntax/method references to implement any such interface. You can even use higher-order functions such as compose, which returns a generic Function type, and pass it to a method which expects a compatible functional interface type.

you cannot change the value of the variable you reference in a closure

This is not a limitation specific to Java. In fact, most FP languages don't support mutable variables of any kind. Note that there is no requirement to use the final keyword on the variable; the concept of effectively final takes care of that.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • This part: <> What do you say about single element arrays, e.g., `final int[] numRef = {0};`? I see this trick used frequently to mutate a variable from a closure. – kevinarpe Jul 19 '23 at 03:09
  • That is one of the possible workarounds for the stated restriction, and the trick is to mutate a non-final member of the object (or array slot) the final variable refers to. Immutability is not transitive in Java. – Marko Topolnik Jul 24 '23 at 13:08
8

It is possible. How do you do it?

First construct a "Functional Interface" (or use one of the provided ones). A functional interface is an interface with a single method. java.lang.Runnable is an example.

Second, write a method that takes a functional interface as a parameter.

public void doAThing(Runnable r) {
    r.run();
}

Third, write a method with the correct signature.

public class MyClass {
    public void runAThing() {
        System.out.println("I executed!");
    }
}

Fourth, call the function passing in a method reference.

MyClass mc = new MyClass();
doAThing(mc::runAThing);

You'll note that none of the classes you've wrote ever explicitly implements Runnable. This is handled for you by the compiler.

You can do something similar using a lamdba expression:

doAThing(() -> System.out.println("I executed as a lamdba expression!"));

To return the function as a value from another function, just return an instance of Runnable.

Sean Reilly
  • 21,526
  • 4
  • 48
  • 62
  • @MiguelGuthridge Thanks for the heads up. I've replaced the link with a link to the Java Language Specification section on Functional Interfaces, which should be a lot more permanent. My only concern is that it's not nearly as tutorial-ish in nature as the link it replaces. I'm interested in your take on the new link, and if you feel it explains things well enough for you. – Sean Reilly Feb 18 '22 at 12:45
  • It's decent now that I know what it's on about, but it would be somewhat difficult to comprehend if a person hadn't already come across it before. It could also be useful to find something that mentions the existence of the `TypeSupplier` interfaces too. – Miguel Guthridge Feb 19 '22 at 00:52
4

Methods are not first class objecs in Java, apart from the already existing usage in reflection, to answer your questions:

  1. Yes, you can pass it on, but it needs to satisfy the signature.

    • For a void method() you use a Runnable, like this:
      Runnable method = this::method if it is in the same class, and then run the actual method with method.run().
    • However for a double method() you need to use a DoubleSupplier, like this: DoubleSupplier method = this::method, and then use it as double d = method.get().
    • And many more signatures, and you can even define your own with Functional Interfaces.
  2. Yes it is possible, but only specific signatures as shown in Point 1.

  3. Lambdas behave exactly as anonymous inner classes, which are closures by itself, Java has had support for closures since they introduced anonymous inner classes. The only thing that is added now is that the syntax is much prettier.

skiwi
  • 66,971
  • 31
  • 131
  • 216
  • RE: point 3, it would be fair to note that they added quite a lot more than just syntax sugar for lambdas. The mechanism is flexible enough to support many different lambda implementations, unlike the old way which forced a complete new class to be created and loaded for each lambda. – Marko Topolnik Mar 20 '14 at 11:04
3

No, not first class functions. Lambda expression are wrapped in a interface, and some syntatic sugar applied for brevity.

But you can;t create a function on its own and pass it around different methods, whether thats a key point or not is a different question.

NimChimpsky
  • 46,453
  • 60
  • 198
  • 311