Functional Interface

WHAT

A functional interface is an interface which has one and only one abstract method defined. Still you can have a default method in it as per Java 8 specification. See what the official docs says about functional interface

A functional interface has exactly one abstract method. Since default methods have an implementation, they are not abstract. If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface’s abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.

HOW

An interface is said to be a functional interface if it is annotated with @FunctionalInterface. The annotation tells nothing but it tells to the compiler that the given interface has one and only one abstract method. So it’s not mandatory to add this annotation to your interfaces, still it’s a good practice to follow.

A valid functional interface is given below.

supplier_ok

See what happens if one more abstract method is being added.

supplier_not_ok

PURPOSE

One of the common use cases of this kinda interface is to pass it’s abstract method around lambda expressions. You’ll get to know once we start going through the examples.

USE CASE

Consider a simple class,

public class SupplierExample {
public static void main(String... args) {
System.out.println("Supplier supplies Refrigerator");
System.out.println("Supplier supplies Washing Maching");
System.out.println("Supplier supplies Microwave Oven");
}
}

This is a facile way to get the items supplied by the supplier. But it’s not proper. Look at the following code.

public class SupplierExample {
public static void main(String... args) {
supply("Refrigerator");
supply("Washing Maching");
supply("Microwave Oven");
}

private static void supply(String item) {
System.out.println("Supplier supplies " + item);
}
}

This is more generic, right ? But it’s always better to write codes to the interface, like this.

public class SupplierExample implements Supplier {
public static void main(String... args) {
SupplierExample supplier = new SupplierExample();
supplier.supply("Refrigerator");
supplier.supply("Washing Maching");
supplier.supply("Microwave Oven");
}

@Override
public void supply(String item) {
System.out.println("Supplier supplies " + item);
}
}

interface Supplier {
void supply(String item);
}

We can achieve this one way or another, like using anonymous inner class.

package com.wordpress.blog.fi;

public class SupplierExample {
public static void main(String... args) {
Supplier supplier = new Supplier() {
@Override
public void supply(String item) {
System.out.println("Supplier supplies " + item);
}
};
supplier.supply("Refrigerator");
supplier.supply("Washing Maching");
supplier.supply("Microwave Oven");
}
}

interface Supplier {
void supply(String item);
}

So far, so good. But since when Java 1.8 released, we have another robust feature available, that is lambda expressions. It’s said to be the most renowned feature of Java 1.8 and it’s a big leap by Java towards functional programming.

First and foremost, see the lambda expression syntax.

(String item) -> {
System.out.println("Supplier supplies " + item);
}

If we have only one statement inside an expression, we are free to remove the parenthesis.

(String item) -> System.out.println("Supplier supplies " + item);

We are also able to remove the data type of item as well. Lambda expression absolutely is an intelligent tool to identify the data type.

item -> System.out.println("Supplier supplies " + item);

Yet another feature of lambda expression is, we can assign our expression to an interface if it is a functional interface, i.e, an interface with one and only one abstract method. When we assign an expression to a functional interface, the compiler will detect the abstract method of the interface and consider this expression as its implementation.

So the expression can be assigned like this.

Supplier supplier = item -> System.out.println("Supplier supplies " + item);

So let’s make some changes to the code and it will be looked like this,

public class SupplierExample {
public static void main(String... args) {
Supplier supplier = item -> System.out.println("Supplier supplies " + item);
supplier.supply("Refrigerator");
supplier.supply("Washing Maching");
supplier.supply("Microwave Oven");
}
}

interface Supplier {
void supply(String item);
}

We can even pass this interface to a method as an argument, and execute it later when and where we need. This is called Behavior Parameterization, i.e, passing behavior as a parameter.

public class SupplierExample {
public static void main(String... args) {
Supplier supplier = item -> System.out.println("Supplier supplies " + item);
supply(supplier);
}

static void supply(Supplier supplier) {
supplier.supply("Refrigerator");
supplier.supply("Washing Maching");
supplier.supply("Microwave Oven");
}
}

interface Supplier {
void supply(String item);
}

Thanks !

Function Composition

Hi Friends,

After a long time, I came back here to make you aware of a feature available in Java 8. Today we are going to learn about Function Composition.

WHAT ?

As is it said, Function Composition is a process to combine two more functions to become a new function.

HOW ?

There are two methods provided to compose/combine functions, and it is available in Function interface. Those methods are andThen and compose. Both methods accept one parameter, of type Function.

WHY TWO ?

It’s true that both methods do the same job. The only difference between these methods is in the order they execute the functions. To be more precise, the compose method executes the parameter function first and the caller function last, but the andThen method executes the caller function first and the parameter function last.

See what javadoc says,

compose
default  Function<V,R> compose(Function<? super V,? extends T> before)
Returns a composed function that first applies the before function to its input, and then applies this function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the composed function.

andThen
default  Function<T,V> andThen(Function<? super R,? extends V> after)
Returns a composed function that first applies this function to its input, and then applies the after function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the composed function.

EXAMPLES

Hope all of you caught up so far. Let’s move on to some examples.

Function quote = s -> "'" + s + "'";
Function toString = Object::toString;
System.out.println(quote.compose(toString).apply(20));
System.out.println(toString.andThen(quote).apply(20));

Output

'20'
'20'

Here, both compose and andThen give the same result, as there’s no much difference in applying quotes before toString and after toString. So here it works fine. Let’s look into another example.

Function multipleBy2 = e -> e * 2;
Function square = e -> e * e;
System.out.println(multipleBy2.compose(square).apply(10));
System.out.println(multipleBy2.andThen(square).apply(10));

Output

200 // (10*10)^2
400 // (10*2)^2

Alas, both results are not same. What happens here is, It’s apparent that in the first operation, square is applied first, then multipleBy2 applied; while in the second operation, multipleBy2 is applied first, then square applied. This is how the compose method and the andThen method works.

MORE EXAMPLES

Now let’s take the leverage of function composition to another level.

Article.java

class Article {
private String author;
private String name;
private List<String> tags;
private Integer likes;
private Integer comments;

public String getAuthor() {
return author;
}

public void setAuthor(String author) {
this.author = author;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public List<String> getTags() {
return tags;
}

public void setTags(List<String> tags) {
this.tags = tags;
}

public Integer getLikes() {
return likes;
}

public void setLikes(Integer likes) {
this.likes = likes;
}

public Integer getComments() {
return comments;
}

public void setComments(Integer comments) {
this.comments = comments;
}

CompositionExample.java

public class CompositionExample {

static List<Article> articles = new ArrayList<>();

private static void constructArticles() {
Article article1 = new Article();
article1.setAuthor("Steve");
article1.setName("Java Collections");
article1.setTags(Arrays.asList("Java", "Collections", "Java 8"));
article1.setLikes(15);
article1.setComments(29);

Article article2 = new Article();
article2.setAuthor("Steve");
article2.setName("Spring Boot");
article2.setTags(Arrays.asList("Java", "Microservices", "Spring Boot"));
article2.setLikes(12);
article2.setComments(15);

Article article3 = new Article();
article3.setAuthor("Steve");
article3.setName("Apache Kafka");
article3.setTags(Arrays.asList("Kafka", "Stream"));
article3.setLikes(9);
article3.setComments(5);

Article article4 = new Article();
article4.setAuthor("Mark");
article4.setName("Hibernate");
article4.setTags(Arrays.asList("Java", "Hibernate", "ORM"));
article4.setLikes(28);
article4.setComments(41);

Article article5 = new Article();
article5.setAuthor("Mark");
article5.setName("Struts");
article5.setTags(Arrays.asList("Apache", "Struts"));
article5.setLikes(52);
article5.setComments(37);

articles.add(article1);
articles.add(article2);
articles.add(article3);
articles.add(article4);
articles.add(article5);
}
}

The method getMostLikedByAuthor()

private static Optional<Article> getMostLikedByAuthor(final String author, final List<Article> articleList) {

BiFunction<String, List<Article>, List<Article>> byAuthor = (name, articles) -> articles.stream()
.filter(a -> a.getAuthor().equals(name)).collect(Collectors.toList());

Function<List<Article>, Optional<Article>> mostLiked = articles -> articles.stream()
.max(Comparator.comparing(Article::getLikes));

return byAuthor.andThen(mostLiked).apply(author, articleList);

}

The method getLeastCommented()

private static Optional<Article> getLeastCommented(final String tag, final List<Article> articleList) {

BiFunction<String, List<Article>, List<Article>> byTag = (name, articles) -> articles.stream()
.filter(a -> a.getTags().contains(name)).collect(Collectors.toList());

Function<List<Article>, Optional<Article>> leastCommented = articles -> articles.stream()
.min(Comparator.comparing(Article::getComments));

return byTag.andThen(leastCommented).apply(tag, articleList);
}

The main() method

public static void main(String [] args) {

constructArticles();

Optional<Article> mostLikedByAuthor = getMostLikedByAuthor("Steve", articles);

if (mostLikedByAuthor.isPresent()) {
System.out.println("Most liked article written by 'Steve' is: " + mostLikedByAuthor.get().getName());
}

Optional<Article> leastCommentedByTag = getLeastCommented("Java", articles);

if (leastCommentedByTag.isPresent()) {
System.out.println("Least commented article tagged with 'Java' is: " + leastCommentedByTag.get().getName());
}
}

See the entire class below.

package com.petrosocial.viewer.xml.PdfExport;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;

public class CompositionExample {

static List<Article> articles = new ArrayList<>();

private static void constructArticles() {
Article article1 = new Article();
article1.setAuthor("Steve");
article1.setName("Java Collections");
article1.setTags(Arrays.asList("Java", "Collections", "Java 8"));
article1.setLikes(15);
article1.setComments(29);

Article article2 = new Article();
article2.setAuthor("Steve");
article2.setName("Spring Boot");
article2.setTags(Arrays.asList("Java", "Microservices", "Spring Boot"));
article2.setLikes(12);
article2.setComments(15);

Article article3 = new Article();
article3.setAuthor("Steve");
article3.setName("Apache Kafka");
article3.setTags(Arrays.asList("Kafka", "Stream"));
article3.setLikes(9);
article3.setComments(5);

Article article4 = new Article();
article4.setAuthor("Mark");
article4.setName("Hibernate");
article4.setTags(Arrays.asList("Java", "Hibernate", "ORM"));
article4.setLikes(28);
article4.setComments(41);

Article article5 = new Article();
article5.setAuthor("Mark");
article5.setName("Struts");
article5.setTags(Arrays.asList("Apache", "Struts"));
article5.setLikes(52);
article5.setComments(37);

articles.add(article1);
articles.add(article2);
articles.add(article3);
articles.add(article4);
articles.add(article5);
}

private static Optional<Article> getMostLikedByAuthor(final String author, final List<Article> articleList) {

BiFunction<String, List<Article>, List<Article>> byAuthor = (name, articles) -> articles.stream()
.filter(a -> a.getAuthor().equals(name)).collect(Collectors.toList());

Function<List<Article>, Optional<Article>> mostLiked = articles -> articles.stream()
.max(Comparator.comparing(Article::getLikes));

return byAuthor.andThen(mostLiked).apply(author, articleList);

}

private static Optional<Article> getLeastCommented(final String tag, final List<Article> articleList) {

BiFunction<String, List<Article>, List<Article>> byTag = (name, articles) -> articles.stream()
.filter(a -> a.getTags().contains(name)).collect(Collectors.toList());

Function<List<Article>, Optional<Article>> leastCommented = articles -> articles.stream()
.min(Comparator.comparing(Article::getComments));

return byTag.andThen(leastCommented).apply(tag, articleList);
}

public static void main(String [] args) {

constructArticles();

Optional<Article> mostLikedByAuthor = getMostLikedByAuthor("Steve", articles);

if (mostLikedByAuthor.isPresent()) {
System.out.println("Most liked article written by 'Steve' is: " + mostLikedByAuthor.get().getName());
}

Optional<Article> leastCommentedByTag = getLeastCommented("Java", articles);

if (leastCommentedByTag.isPresent()) {
System.out.println("Least commented article tagged with 'Java' is: " + leastCommentedByTag.get().getName());
}
}
}

class Article {
private String author;
private String name;
private List<String> tags;
private Integer likes;
private Integer comments;

public String getAuthor() {
return author;
}

public void setAuthor(String author) {
this.author = author;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public List<String> getTags() {
return tags;
}

public void setTags(List<String> tags) {
this.tags = tags;
}

public Integer getLikes() {
return likes;
}

public void setLikes(Integer likes) {
this.likes = likes;
}

public Integer getComments() {
return comments;
}

public void setComments(Integer comments) {
this.comments = comments;
}

}

Now, let’s execute this code.

Output

Most liked article written by 'Steve' is: Java Collections
Least commented article tagged with 'Java' is: Spring Boot

That’s it. Now you have moved towards the end of this article and you are on the verge of experiencing function composition. Try it and have fun.

Thank you.