Hao Han Lim
Hao Han Lim

Reputation: 31

Java example: Why can a function in this w3schools example run when it is not defined?

Here is the issue, you can find it in w3schools lamda expressions chapter last example:

interface StringFunction {
  String run(String str);
}

And:

public class Main {
  public static void main(String[] args) {
    StringFunction exclaim = (s) -> s + "!";
    StringFunction ask = (s) -> s + "?";
    printFormatted("Hello", exclaim);
    printFormatted("Hello", ask);
  }
  public static void printFormatted(String str, StringFunction format) {
    String result = format.run(str);
    System.out.println(result);
  }
}

So from my understanding,the code here doesnt explicitly define the function '.run()' in the interface 'StringFunction', only the parameters is stated in it.

And I believe one needs to implement this class by making another class to further define the behaviour of this function. Therefore the major confusion here is that '.run()' can for some reason work without any defintition, so if it is not a built-in function of java please someone explain to me as to why and how is this possible. The fact that 'StringFunction' can be used as a class for 'exclaim' and 'ask' is also very confusing without any definition.

I just started out with java so I hope for your understanding.

Upvotes: 2

Views: 149

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 339827

The other Answers are correct about your StringFunction being a functional interface because it defines only a single abstract method. You later implement that functional interface by way of a lambda. (See tutorial by Oracle.) I’ll add one more thought.

java.lang.FunctionalInterface

If you were intending for StringFunction to be a functional interface, you can communicate that intent by annotating with FunctionalInterface.

@FunctionalInterface          // ⬅️ (a) Communicates your intent. (b) Protects against later adding more methods. 
interface StringFunction {
  String run(String str);
}

Besides communicating intent, this annotation protects you in the future. If a programmer later adds another method to your interface, the compiler reports an error. The error explains how the additional method violates the contract promised by that annotation.

However, note that use of the FunctionalInterface annotation is optional. Your code so demonstrates. To quote the Javadoc:

… the compiler will treat any interface meeting the definition of a functional interface as a functional interface regardless of whether or not a FunctionalInterface annotation is present on the interface declaration.

While technically optional, I do recommend using this annotation.

For a complete definition of a functional interface, see this page of the Java Language Specification.

Upvotes: 4

Geba
Geba

Reputation: 1122

Functional interface

StringFunction is a functional interface. In other words it is an interface with a single abstract method.
An abstract method is a method without definition (without body).

Such interfaces can be implemented using a lambda expression. As it is done in your example.

So StringFunction exclaim = (s) -> s + "!" is an implementation of StringFunction and an instance of that implementation.

You can think of StringFunction exclaim = (s) -> s + "!" as a short version of following:

class ExclamationAppender implements StringFunction {
    @Override
    public String run(String s) {
        return s + "!";
    }
}

StringFunction exclaim = new ExclamationAppender();

Upvotes: 10

Maksim Banit
Maksim Banit

Reputation: 111

In your code, the interface StringFunction has only one method: run(String str). In Java, such interfaces are called functional interfaces, and they have a useful feature—lambda expressions.

When you write:

StringFunction exclaim = (s) -> s + "!";

Java understands that this is just a shorthand way to implement the run() method because StringFunction has no other methods.

If you were to write the code in a traditional way, it would look like this:

class ExclaimFunction implements StringFunction {
  @Override
  public String run(String str) {
    return str + "!";
  }
}

And you would have to use it like this:

StringFunction exclaim = new ExclaimFunction();

But why create unnecessary classes when you can do everything in one line?

Java automatically creates an anonymous class behind the scenes, which is why run() works even though you haven’t explicitly defined it anywhere. This is just a way to make the code shorter and more convenient.

Upvotes: 4

Related Questions