Functional programming in Java developed with the introduction of lambda expressions and functional interfaces (starting from Java 8).
Background
Before Java 8, all interfaces were a set of abstract methods, and the paradigm was oriented towards OOP. With the introduction of functional interfaces and lambda expressions, it became possible to write more concise code and follow FP principles, increasing readability and expressiveness of the code.
Problem
Code related to event handling, collections, or asynchronous logic became verbose: it was necessary to create separate classes or anonymous inner classes. This complicated code maintenance and scaling.
Solution
A functional interface is an interface with exactly one abstract method. It can be used as a target type for a lambda expression. The standard library introduced type-specific functional interfaces such as Function<T, R>, Predicate<T>, Supplier<T>, Consumer<T>, as well as the ability to create your own interfaces.
Example code:
import java.util.function.Function; public class FunctionalExample { public static void main(String[] args) { // Standard functional interface Function Function<String, Integer> stringLength = s -> s.length(); System.out.println(stringLength.apply("Java")); // Will print 4 } }
Key features:
Can a functional interface be declared with multiple abstract methods if the other methods have default or static implementations?
No, a functional interface can only contain one abstract method. A default (default) or static method is allowed.
Can a functional interface inherit from another interface with multiple abstract methods?
No, if the resulting interface has more than one abstract method, it ceases to be functional and cannot be used for substituting a lambda expression.
How does a functional interface in Java differ from SAM interfaces in other languages, such as C#?
In Java, there is no direct keyword for declaring SAM interfaces before the introduction of the @FunctionalInterface annotation. Unlike C#, where delegate clearly defines the signature, in Java it is enough to have one abstract method and an optional annotation for the compiler.
@FunctionalInterface annotation — the compiler does not immediately issue an error if the interface ceases to be functional.In a large project, it was decided to use lambdas everywhere, including where entities represented data not directly related to business logic. As a result, it became difficult to track complex logic, lambdas concealed the intentions of the code, and debugging became challenging.
Pros:
Cons:
In another project, a thorough analysis was conducted to determine which interfaces were suitable for FP. They used Predicate, Function, and their own interfaces for processing collections and events. For entities and data storage, FP was not applied.
Pros:
Cons: