1. Overview
In this post, we will learn the Java 8 the functional interface with examples.
Key points about the functional interface:
- An Interface that contains exactly one abstract method is known as a functional interface.
- It can have any number of default, static methods but can contain only one abstract method. It can also declare methods of the object class.
- Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces. It is a new feature in Java 8, which helps to achieve a functional programming approach.
- A functional interface can extend another interface only when it does not have any abstract method.
- The Java API has many one-method interfaces such as Runnable, Callable, Comparator, ActionListener, and others. They can be implemented and instantiated using anonymous class syntax.
2. Examples of Custom Functional Interface
Create a custom Sayable interface is a functional interface annotated with @FunctionalInterface.
The @FunctionalInterface annotation indicates that an interface is a functional interface and contains exactly one abstract method.
2.1 Custom Functional Interface Example
Let's create a Sayable interface annotated with @FunctionalInterface annotation.
@FunctionalInterface
interface Sayable{
void say(String msg); // abstract method
}
Let's demonstrate a custom functional interface via the main() method.
public class FunctionalInterfacesExample {
public static void main(String[] args) {
Sayable sayable = (msg) -> {
System.out.println(msg);
};
sayable.say("Say something ..");
}
}
3. Java 8 Predefined-Functional Interfaces
Java 8 provides predefined functional interfaces to deal with functional programming by using lambda and method references.
Predefined-Functional Interfaces Examples
Let's discuss Java Predefined-Functional Interfaces with examples.
Step 1: Create a Person class, this Person class is used to demonstrate Predefined-Functional Interfaces examples.
public class Person {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3.1 Predicate
- We need a function for checking a condition. A Predicate is one such function accepting a single argument to evaluate to a boolean result.
- It has a single method test that returns the boolean value.
Predicate interface from JDK 8: Let's look at the internal implementation of the Predicate interface. Predicate interface contains exactly one abstract method test(T t). Note that it also contains a default, static methods.
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
Predicate Example :
public class PredicateExample {
public static void main(String[] args) {
Predicate < Person > predicate = (person) -> person.getAge() > 28;
boolean result = predicate.test(new Person("ramesh", 29));
System.out.println(result);
}
}
3.2 Function
Function interface from JDK 8: Let's look at the internal implementation of the Function interface. The function interface contains exactly one abstract method apply(T t). Note that it also contains a default, static methods.
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
Function Example :
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
// convert centigrade to fahrenheit
Function < Integer, Double > centigradeToFahrenheitInt = x -> new Double((x * 9 / 5) + 32);
// String to an integer
Function < String, Integer > stringToInt = x -> Integer.valueOf(x);
System.out.println(" String to Int: " + stringToInt.apply("4"));
Function < PersonEntity, PersonDTO > function = (entity) -> {
return new PersonDTO(entity.getName(), entity.getAge());
};
PersonDTO personDTO = function.apply(new PersonEntity("ramesh", 20));
System.out.println(personDTO.getName());
System.out.println(personDTO.getAge());
}
}
class PersonEntity {
private String name;
private int age;
public PersonEntity(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class PersonDTO {
private String name;
private int age;
public PersonDTO(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3.3 Supplier
Supplier interface from JDK 8: Let's look at the internal implementation of the Supplier interface. The supplier interface contains exactly one abstract method get(T t). Hence we can apply lambda expression to it.
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
Supplier Example :
import java.util.function.Supplier;
public class SuppliersExample {
public static void main(String[] args) {
Supplier<Person> supplier = () -> {
return new Person("Ramesh", 30 );
};
Person p = supplier.get();
System.out.println("Person Detail:\n" + p.getName() + ", " + p.getAge());
}
}
3.4 Consumer
Consumer interface from JDK 8: Let's look at the internal implementation of the Consumer interface. The consumer interface contains exactly one abstract method accept(T arg0). Hence we can apply lambda expression to it.
@FunctionalInterface
public interface Consumer<T> {
void accept(T arg0);
default Consumer<T> andThen(Consumer<? super T> arg0) {
Objects.requireNonNull(arg0);
return (arg1) -> {
this.accept(arg1);
arg0.accept(arg1);
};
}
}
Consumer Example :
public class ConsumersExample {
public static void main(String[] args) {
List<Person> listOfPerson = new ArrayList<Person>();
listOfPerson.add(new Person("abc", 27));
listOfPerson.add(new Person("mno", 26));
listOfPerson.add(new Person("pqr", 28));
listOfPerson.add(new Person("xyz", 27));
listOfPerson.forEach((person) -> {
System.out.println(" Person name : " + person.getName());
System.out.println(" Person age : " + person.getAge());
});
// Second example
Consumer<Person> consumer = (person) -> {
System.out.println(person.getName());
System.out.println(person.getAge());
};
consumer.accept(new Person("Ramesh", 30));
}
}
To define lambdas with two arguments, we have to use additional interfaces that contain “Bi” keyword in their names: BiFunction, ToDoubleBiFunction, ToIntBiFunction, and ToLongBiFunction.
Let’s use a BiFunction implementation that receives a key and an old value to calculate a new value for the salary and return it.
3.5 BiFunction
BiFunction interface from JDK 8: Let's look at the internal implementation of BiFunction interface. BiFunction interface contains exactly one abstract method apply(T arg0, U arg1). Hence we can apply lambda expression to it.
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T arg0, U arg1);
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> arg0) {
Objects.requireNonNull(arg0);
return (arg1, arg2) -> {
return arg0.apply(this.apply(arg1, arg2));
};
}
}
BiFunction Example :
public class BiFunctionExample {
public static void main(String[] args) {
BiFunction<Person, Person, Integer> biFunction = (p1,p2) -> {
return p1.getAge() + p2.getAge();
};
int totalAge = biFunction.apply(new Person("Ramesh", 10),
new Person("ram", 10));
System.out.println(totalAge);
}
}
3.6 BiConsumer
BiConsumer interface from JDK 8: Let's look at the internal implementation of BiConsumer interface. BiConsumer interface contains exactly one abstract method accept(T arg0, U arg1). Hence we can apply lambda expression to it.
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T arg0, U arg1);
default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> arg0) {
Objects.requireNonNull(arg0);
return (arg1, arg2) -> {
this.accept(arg1, arg2);
arg0.accept(arg1, arg2);
};
}
}
BiConsumer Example :
public class BiConsumersExample { public static void main(String[] args) { BiConsumer<Person, Person> biConsumer = (p1, p2) -> { System.out.println(" print first persion"); System.out.println(p1.getName()); System.out.println(" print second persion"); System.out.println(p2.getName()); }; biConsumer.accept(new Person("Ramesh", 10), new Person("ram", 10)); } }
You can also define your own custom functional interface. Following is the list of a functional interface that is placed in java.util.function package.
The source code of this article is available on GitHub Repository.
Please write comments, if you want to give any suggestions or feedback about this article would be appreciated.
Summary
- A functional interface is an interface that has exactly one abstract method.
- Since default methods have an implementation, they are not abstract so a functional interface can have any number of them.
- If an interface declares an abstract method with the signature of one of the methods of java.lang.Object, it doesn't count toward the functional interface method count.
- A functional interface is valid when it inherits a method that is equivalent but not identical to another.
- An empty interface is not considered a functional interface.
- A functional interface is valid even if the @FunctionalInterface annotation would be omitted.
- Functional interfaces are the basis of lambda expressions.
The source code of this article is available on GitHub Repository.
Please write comments, if you want to give any suggestions or feedback about this article would be appreciated.
If you like my articles and want similar kind of stuff, connect with me on Google +, Facebook, Twitter, GitHub, and StackOverflow.
Check out our top viewed Java Guides and Java/J2EE Best practices. I hope you like it.
Happy Learning and Keep Coding !!!!.
Happy Learning and Keep Coding !!!!.
4. Related Java 8 Top Posts
- Java 8 Lambda Expressions
- Java 8 Functional Interfaces
- Java 8 Method References
- Java 8 Stream API
- Java 8 Optional Class
- Java 8 Collectors Class
- Java 8 StringJoiner Class
- Java 8 Static and Default Methods in Interface
- Guide to Java 8 forEach Method
- Handle NullPointerException using Java 8 Optional Class
- How to Use Java 8 Stream API in Java Projects
- Migrating Source Code to Java 8
Comments
Post a comment