Skip to main content

Java 8 Lambdas, Functional Interface & "static" and "default" methods

Java 8: "static" and "default" methods in interface

All "interface" methods are implicitly "public" and "abstract," unless declared as "static" or "default."

As of Java 8, it is now possible to inherit concrete methods (static and default) from an interface.

The implementation class is not required to implement "static" or "default" methods.

Optionally, an implementation class can inherit "default" interface methods but not "static" interface methods.

Functional Interfaces

A functional interface is an interface that contains only one abstract method.

In this SAM (single abstract method) rule, "default," "static," and methods inherited from "Object" class do not count.

In the example above, the "int hashCode()" method is overridden from the "Object" class.

Java 8 lambdas

A "Lambda" expression is an instance of a class that implements a functional interface.

Lambdas resemble "methods," but they are instances, not "methods" or "anonymous-methods."

Using a custom Functional Interface

"Lambda" expressions only work with Functional Interfaces.

A functional interface defines the target type of a lambda expression.

The "var" keyword introduced in "Java 10" cannot be used to infer a lambda expression. ("Cannot infer type": lambda expressions require an explicit target type.)

The "java.util.function" package

The "java.util.function" package comes with a set of pre-defined functional interfaces.

1) Predicate

Predicate is a functional interface that has the functional method "boolean test(T t)". It accepts "one argument" and returns a boolean (true if the input argument matches the predicate, otherwise false).

1.1) Predicate as a method parameter

Predicates can be passed as method parameters:

1.2) Composed predicate (AND and OR)

The "default Predicate and(Predicate other)" method in the "Predicate" interface is a "non-abstract" method. It returns the logical AND of this predicate and the other predicate.

The "default Predicate or(Predicate other)" method in the "Predicate" interfaceis a "non-abstract" method. It returns the logical OR of this predicate and the other predicate.


1.3) Predicate negation

The "default Predicate negate()" method in the "Predicate" interface is a "non-abstract" method. It returns a predicate that represents the logical negation of this predicate.

2) BiPredicate

BiPredicate is a functional interface that has the functional method "boolean test(T t, U u)". It accepts "two arguments" and returns a boolean (true if the input arguments match the predicate, otherwise false).

The "BiPredicate" interface also contains three "default" "non-abstract" methods: and(), or(), and negate().

3) Supplier

Supplier is a functional interface that has the functional method "T get()". It accepts "zero arguments" and returns a result of type T.

4) Consumer

Consumer is a functional interface that has the functional method "void accept(T t)". It accepts a single argument and returns no result.

The "default Consumer andThen(Consumer after)" method in the "Consumer" interface is a "non-abstract" method. It returns a composed Consumer that performs in sequence this operation followed by the after operation.

My Name is: Leonardo DiCaprio
My Name is: LEONARDO DICAPRIO

5) BiConsumer

BiConsumer is a functional interface that has the functional method "void accept(T t, U u)". It accepts two arguments and returns no result.

The "default BiConsumer andThen(BiConsumer after)" is a "default" "non-abstract" method in the "BiConsumer" interface. It returns a composed BiConsumer that performs in sequence this operation followed by the after operation.

My Name is 'Leonardo DiCaprio', I am '32'.
My Name is 'LEONARDO DICAPRIO', I am '32'.

6) Function

Function is a functional interface that has the functional method "R apply(T t)". It accepts one argument and returns one result.

The "default Function compose(Function before)" is a "default" "non-abstract" method in the "Function" interface.

It returns a composed function that first applies the before function to its input, and then applies this function to the result.

The "default Function andThen(Function after)" is a "default" "non-abstract" method in the "Function" interface.

It returns a composed function that first applies this function to its input, and then applies the after function to the result.


7) BiFunction

BiFunction is a functional interface that has the functional method "R apply(T t, U u)". It accepts two arguments and produces a result.

The "default BiFunction andThen(Function after)" is a "default" "non-abstract" method in the "BiFunction" interface.

It returns a composed function that first applies this function to its input, and then applies the after function to the result.

8) UnaryOperator

UnaryOperator is a functional interface that extends another functional interface Function. Its functional method is R apply(T t), the one extended from Function.

UnaryOperator represents an operation on a single operand that produces a result of the same type as its operand.

This is a specialization of Function for the case where the operand and result are of the same type.

The "static UnaryOperator identity()" is a "static" "non-abstract" method in the "UnaryOperator" interface. It returns a unary operator that always returns its input argument.

9) BinaryOperator

BinaryOperator is a functional interface that extends another functional interface BiFunction. Its functional method is R apply(T t, U u), the one extended from BiFunction.

It represents an operation upon two operands of the same type, producing a result of the same type as the operands.

This is a specialization of BiFunction for the case where the operands and the result are all of the same type.

The "static BinaryOperator minBy(Comparator comparator)" is a "static" "non-abstract" method in the "BinaryOperator" interface. It returns a BinaryOperator which returns the lesser of two elements according to the specified Comparator.

The "static BinaryOperator maxBy(Comparator comparator)" is a "static" "non-abstract" method in the "BinaryOperator" interface. It returns a BinaryOperator which returns the greater of two elements according to the specified Comparator.

Lambda Benefits

1) A lambda helps in creating a function without belonging to any class.

2) It allows you to treat a piece of functionality as a method argument or code as data.

3) A lambda expression can be passed around as if it were an object and executed on demand.

Comments

Popular posts from this blog

Deploying Spring Boot microservices on Kubernetes Cluster

This article guides you through the deployment of two Spring Boot microservices, namely "order-service" and "inventory-service," on Kubernetes using "MiniKube" . We will establish communication between them, with "order-service" making calls to an endpoint in "inventory-service." Additionally, we will configure "order-service" to be accessible from the local machine's browser . 1) Create Spring Boot microservices The Spring Boot microservices, "order-service" and "inventory-service," have been developed and can be found in this GitHub repository. If you are interested in learning more about creating Spring Boot REST microservices, please refer to this or this (Reactive) link. 2) Build Docker Images The Docker images for both "order-service" and "inventory-service" have already been generated and deployed on DockerHub, as shown below. codeburps/order-service cod...

Circuit Breaker Pattern with Resilience4J in a Spring Boot Application

Read Also: Spring Cloud Circuit Breaker + Resilience4j Resilience4j is a lightweight fault tolerance library that draws inspiration from Netflix Hystrix but is specifically crafted for functional programming. The library offers higher-order functions, known as decorators , designed to augment any functional interface, lambda expression, or method reference with features such as Circuit Breaker, Rate Limiter, Retry, or Bulkhead . These functionalities can be seamlessly integrated within a project, class, or even applied to a single method. It's possible to layer multiple decorators on any functional interface, lambda expression, or method reference, allowing for versatile and customizable fault tolerance. While numerous annotation-based implementations exist online, this article focuses solely on the reactive approach using router predicates and router functions . How Circuit Breaker Pattern works? In general, a circuit breaker functions as an automatic electrical s...

How to create a basic Spring 6 project using Maven

Below is a step-by-step guide to creating a basic Spring project using Maven. 1) Create a Maven Project Use the following Maven command to create a new Maven project. mvn archetype:generate -DgroupId=com.tb -DartifactId=spring-demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false 2) Import in IntelliJ IDEA If you haven't already, open IntelliJ IDEA on your system. Go to "File" > "New" > "Project from Existing Sources..." . In the file dialog, navigate to the directory where your Maven project is located. Select the pom.xml file within the project directory and click "Open." 3) Update pom.xml In total, the application requires the below-mentioned dependencies: 4) Create Spring Configuration Create a Java configuration class that uses annotations to define your Spring beans and their dependencies. This class should be annotated with @Configuration . 5) Create the Main Application C...