3.1.2 Functional Interfaces Explained
Functional interfaces in Java are interfaces that contain exactly one abstract method. They are a key part of Java's support for functional programming, allowing developers to use lambda expressions and method references to create concise and expressive code.
Key Concepts
1. Single Abstract Method (SAM)
A functional interface must have exactly one abstract method. This single abstract method (SAM) is the core of the interface and defines the behavior that can be implemented using lambda expressions or method references.
Example
@FunctionalInterface interface MyFunctionalInterface { void doSomething(); }
2. @FunctionalInterface Annotation
The @FunctionalInterface
annotation is used to indicate that an interface is intended to be a functional interface. While this annotation is optional, it provides a compile-time check to ensure that the interface adheres to the functional interface rules.
Example
@FunctionalInterface interface MyFunctionalInterface { void doSomething(); }
3. Default and Static Methods
Functional interfaces can contain default and static methods in addition to the single abstract method. These methods provide additional functionality without affecting the core behavior defined by the abstract method.
Example
@FunctionalInterface interface MyFunctionalInterface { void doSomething(); default void doSomethingElse() { System.out.println("Doing something else"); } static void doStaticThing() { System.out.println("Doing a static thing"); } }
Explanation and Examples
Single Abstract Method (SAM) Example
Consider the following functional interface that defines a single abstract method:
@FunctionalInterface interface MyFunctionalInterface { void doSomething(); } public class Main { public static void main(String[] args) { MyFunctionalInterface myFunc = () -> System.out.println("Doing something"); myFunc.doSomething(); // Output: Doing something } }
In this example, the MyFunctionalInterface
interface has a single abstract method doSomething()
, which is implemented using a lambda expression.
@FunctionalInterface Annotation Example
Consider the following functional interface with the @FunctionalInterface
annotation:
@FunctionalInterface interface MyFunctionalInterface { void doSomething(); } public class Main { public static void main(String[] args) { MyFunctionalInterface myFunc = () -> System.out.println("Doing something"); myFunc.doSomething(); // Output: Doing something } }
The @FunctionalInterface
annotation ensures that the interface adheres to the functional interface rules, providing a compile-time check.
Default and Static Methods Example
Consider the following functional interface with default and static methods:
@FunctionalInterface interface MyFunctionalInterface { void doSomething(); default void doSomethingElse() { System.out.println("Doing something else"); } static void doStaticThing() { System.out.println("Doing a static thing"); } } public class Main { public static void main(String[] args) { MyFunctionalInterface myFunc = () -> System.out.println("Doing something"); myFunc.doSomething(); // Output: Doing something myFunc.doSomethingElse(); // Output: Doing something else MyFunctionalInterface.doStaticThing(); // Output: Doing a static thing } }
In this example, the MyFunctionalInterface
interface includes a default method doSomethingElse()
and a static method doStaticThing()
, in addition to the single abstract method doSomething()
.
Analogies
Think of a functional interface as a recipe that specifies exactly one main dish (the abstract method) but can also include optional side dishes (default methods) and special instructions (static methods). The main dish is the core of the recipe, while the side dishes and instructions provide additional value without changing the essence of the main dish.
By mastering functional interfaces, you can leverage the power of lambda expressions and method references to write more concise and expressive code in your Java SE 11 applications.