Java 8 Method References & Lambdas

Java Method References and Lambda Expressions Explained

Understanding Java Method References and Lambda Expressions Explained is essential for writing cleaner, more functional-style code in modern Java. These features, introduced in Java 8, simplify anonymous class usage and improve code readability and reusability. In this article, we’ll break down how method references and lambda expressions work, when to use them, and how they can streamline your Java development workflow.

Java Method References and Lambda Expressions as Implementations of Functional Interfaces

In Java, a functional interface is an interface that contains exactly one abstract method. Because there is only one method to implement, a functional interface can be implemented using either a lambda expression or a method reference, provided the method signature is compatible.

Consider the following example:

@FunctionalInterface
interface Greet {
void greetings();
}
class MessageBoard {
public static void printMe() {
System.out.println("Hi");
}
void printDetail() {
System.out.println("end");
}
}
interface MessageBoardFactory {
MessageBoard create();
}
public class MethodReferenceDemo {
public static void main(String[] args) {
// Static method reference
Greet greet = MessageBoard::printMe;
greet.greetings();
// Bound instance method reference
MessageBoard messageBoard = new MessageBoard();
Greet greet1 = messageBoard::printDetail;
greet1.greetings();
// Unbound instance method reference
Consumer<MessageBoard> messageBoardConsumer = MessageBoard::printDetail;
messageBoardConsumer.accept(new MessageBoard());
// Constructor reference
MessageBoardFactory messageBoardFactory = MessageBoard::new;
MessageBoard messageBoard1 = messageBoardFactory.create();
messageBoard1.printDetail();
}
}

When we write:

Greet greet = MessageBoard::printMe;

or

Greet greet1 = messageBoard::printDetail;

These method references are valid because their signatures are compatible with the signature of greetings(). This works because:

  • Java sees that MessageBoard::printMe and messageBoard::printDetail satisfy the requirement for greetings() and treats these methods as if they’re implementations of greetings().
  • The signature of Greet‘s greetings() method matches the methods we reference in MessageBoard.

Matching Java Method Reference Signatures

For a method reference to be used with a functional interface, the method referenced must have a compatible signature with the abstract method in that functional interface.

Here:

  • Greet has the void greetings() method, which takes no parameters and returns void.
  • Both printMe() (static method) and printDetail() (instance method) in MessageBoard also have the same signature: void return type and no parameters.

Because the signatures match, Java can “assign” MessageBoard::printMe and messageBoard::printDetail to Greet greetings().

No Inheritance Relationship Required for Java Method References

Unlike traditional object-oriented programming (OOP) where method access usually requires an inheritance relationship (e.g., MessageBoard would have to implement Greet), functional interfaces and lambda expressions/method references break that requirement. The key is that only the method signature compatibility is necessary; no inheritance or direct relationship is required.

This feature allows Java to use functional interfaces more flexibly:

  • Any class with a compatible method can be used with a functional interface, regardless of inheritance.
  • This approach is common in functional programming paradigms, where the goal is to focus on functionality (method matching) rather than object hierarchies.

Java’s Internal Handling of Method References

When you use a method reference like MessageBoard::printMe, Java internally treats it as if you’re implementing the greetings() method in Greet by delegating it to printMe(). Similarly, messageBoard::printDetail is treated as if greetings() calls printDetail() on an instance of MessageBoard. Java essentially “adapts” the MessageBoard method to fit the Greet interface.

Summary

  • Method references work with functional interfaces through signature compatibility, not through inheritance.
  • A functional interface defines a single abstract method.
  • A method reference provides an implementation for that method.
  • The referenced method only needs a compatible parameter list and return type.
  • The containing class does not need to implement the functional interface.
  • Method references are essentially shorthand for lambda expressions.
  • Internally, Java creates an implementation of the functional interface that delegates to the referenced method.
  • This flexibility allows Java to separate behavior from class hierarchies, making code more concise and promoting a more functional programming style.

Helpful Links:


Discover more from Rotebit

Subscribe to get the latest posts sent to your email.

1 Comment

Leave a Reply