Java 8 Functional Interfaces

Filed Under: Java

Welcome to the Java 8 functional interfaces example tutorial. Java has always been an Object Oriented Programming language. What is means that everything in java programming revolves around Objects (except some primitive types for simplicity). We don’t have only functions in java, they are part of Class and we need to use the class/object to invoke any function.

Java 8 Functional Interfaces

java 8 functional interfaces
If we look into some other programming languages such as C++, JavaScript; they are called functional programming language because we can write functions and use them when required. Some of these languages support Object Oriented Programming as well as Functional Programming.

Being object oriented is not bad, but it brings a lot of verbosity to the program. For example, let’s say we have to create an instance of Runnable. Usually we do it using anonymous classes like below.


Runnable r = new Runnable(){
			@Override
			public void run() {
				System.out.println("My Runnable");
			}};

If you look at the above code, the actual part that is of use is the code inside run() method. Rest all of the code is because of the way java programs are structured.

Java 8 Functional Interfaces and Lambda Expressions help us in writing smaller and cleaner code by removing a lot of boiler-plate code.

Java 8 Functional Interface

An interface with exactly one abstract method is called Functional Interface. @FunctionalInterface annotation is added so that we can mark an interface as functional interface.

It is not mandatory to use it, but it’s best practice to use it with functional interfaces to avoid addition of extra methods accidentally. If the interface is annotated with @FunctionalInterface annotation and we try to have more than one abstract method, it throws compiler error.

The major benefit of java 8 functional interfaces is that we can use lambda expressions to instantiate them and avoid using bulky anonymous class implementation.

Java 8 Collections API has been rewritten and new Stream API is introduced that uses a lot of functional interfaces. Java 8 has defined a lot of functional interfaces in java.util.function package. Some of the useful java 8 functional interfaces are Consumer, Supplier, Function and Predicate.

You can find more detail about them in Java 8 Stream Example.

java.lang.Runnable is a great example of functional interface with single abstract method run().

Below code snippet provides some guidance for functional interfaces:


interface Foo { boolean equals(Object obj); }
// Not functional because equals is already an implicit member (Object class)

interface Comparator<T> {
 boolean equals(Object obj);
 int compare(T o1, T o2);
}
// Functional because Comparator has only one abstract non-Object method

interface Foo {
  int m();
  Object clone();
}
// Not functional because method Object.clone is not public

interface X { int m(Iterable<String> arg); }
interface Y { int m(Iterable<String> arg); }
interface Z extends X, Y {}
// Functional: two methods, but they have the same signature

interface X { Iterable m(Iterable<String> arg); }
interface Y { Iterable<String> m(Iterable arg); }
interface Z extends X, Y {}
// Functional: Y.m is a subsignature & return-type-substitutable

interface X { int m(Iterable<String> arg); }
interface Y { int m(Iterable<Integer> arg); }
interface Z extends X, Y {}
// Not functional: No method has a subsignature of all abstract methods

interface X { int m(Iterable<String> arg, Class c); }
interface Y { int m(Iterable arg, Class<?> c); }
interface Z extends X, Y {}
// Not functional: No method has a subsignature of all abstract methods

interface X { long m(); }
interface Y { int m(); }
interface Z extends X, Y {}
// Compiler error: no method is return type substitutable

interface Foo<T> { void m(T arg); }
interface Bar<T> { void m(T arg); }
interface FooBar<X, Y> extends Foo<X>, Bar<Y> {}
// Compiler error: different signatures, same erasure

Lambda Expression

Lambda Expression are the way through which we can visualize functional programming in the java object oriented world. Objects are the base of java programming language and we can never have a function without an Object, that’s why Java language provide support for using lambda expressions only with functional interfaces.

Since there is only one abstract function in the functional interfaces, there is no confusion in applying the lambda expression to the method. Lambda Expressions syntax is (argument) -> (body). Now let’s see how we can write above anonymous Runnable using lambda expression.


Runnable r1 = () -> System.out.println("My Runnable");

Let’s try to understand what is happening in the lambda expression above.

  • Runnable is a functional interface, that’s why we can use lambda expression to create it’s instance.
  • Since run() method takes no argument, our lambda expression also have no argument.
  • Just like if-else blocks, we can avoid curly braces ({}) since we have a single statement in the method body. For multiple statements, we would have to use curly braces like any other methods.

Why do we need Lambda Expression

  1. Reduced Lines of Code
    One of the clear benefit of using lambda expression is that the amount of code is reduced, we have already seen that how easily we can create instance of a functional interface using lambda expression rather than using anonymous class.
  2. Sequential and Parallel Execution Support

    Another benefit of using lambda expression is that we can benefit from the Stream API sequential and parallel operations support.

    To explain this, let’s take a simple example where we need to write a method to test if a number passed is prime number or not.

    Traditionally we would write it’s code like below. The code is not fully optimized but good for example purpose, so bear with me on this.

    
    //Traditional approach
    private static boolean isPrime(int number) {		
    	if(number < 2) return false;
    	for(int i=2; i<number; i++){
    		if(number % i == 0) return false;
    	}
    	return true;
    }
    

    The problem with above code is that it’s sequential in nature, if the number is very huge then it will take significant amount of time. Another problem with code is that there are so many exit points and it’s not readable. Let’s see how we can write the same method using lambda expressions and stream API.

    
    //Declarative approach
    private static boolean isPrime(int number) {		
    	return number > 1
    			&& IntStream.range(2, number).noneMatch(
    					index -> number % index == 0);
    }
    

    IntStream is a sequence of primitive int-valued elements supporting sequential and parallel aggregate operations. This is the int primitive specialization of Stream.

    For more readability, we can also write the method like below.

    
    private static boolean isPrime(int number) {
    	IntPredicate isDivisible = index -> number % index == 0;
    	
    	return number > 1
    			&& IntStream.range(2, number).noneMatch(
    					isDivisible);
    }
    

    If you are not familiar with IntStream, it’s range() method returns a sequential ordered IntStream from startInclusive (inclusive) to endExclusive (exclusive) by an incremental step of 1.

    noneMatch() method returns whether no elements of this stream match the provided predicate. It may not evaluate the predicate on all elements if not necessary for determining the result.

  3. Passing Behaviors into methods

    Let’s see how we can use lambda expressions to pass behavior of a method with a simple example. Let’s say we have to write a method to sum the numbers in a list if they match a given criteria. We can use Predicate and write a method like below.

    
    public static int sumWithCondition(List<Integer> numbers, Predicate<Integer> predicate) {
    	    return numbers.parallelStream()
    	    		.filter(predicate)
    	    		.mapToInt(i -> i)
    	    		.sum();
    	}
    

    Sample usage:

    
    //sum of all numbers
    sumWithCondition(numbers, n -> true)
    //sum of all even numbers
    sumWithCondition(numbers, i -> i%2==0)
    //sum of all numbers greater than 5
    sumWithCondition(numbers, i -> i>5)
    
  4. Higher Efficiency with Laziness

    One more advantage of using lambda expression is the lazy evaluation, for example let’s say we need to write a method to find out the maximum odd number in the range 3 to 11 and return square of it.

    Usually we will write code for this method like this:

    
    private static int findSquareOfMaxOdd(List<Integer> numbers) {
    		int max = 0;
    		for (int i : numbers) {
    			if (i % 2 != 0 && i > 3 && i < 11 && i > max) {
    				max = i;
    			}
    		}
    		return max * max;
    	}
    

    Above program will always run in sequential order but we can use Stream API to achieve this and get benefit of Laziness-seeking. Let’s see how we can rewrite this code in functional programming way using Stream API and lambda expressions.

    
    public static int findSquareOfMaxOdd(List<Integer> numbers) {
    		return numbers.stream()
    				.filter(NumberTest::isOdd) 		//Predicate is functional interface and
    				.filter(NumberTest::isGreaterThan3)	// we are using lambdas to initialize it
    				.filter(NumberTest::isLessThan11)	// rather than anonymous inner classes
    				.max(Comparator.naturalOrder())
    				.map(i -> i * i)
    				.get();
    	}
    
    	public static boolean isOdd(int i) {
    		return i % 2 != 0;
    	}
    	
    	public static boolean isGreaterThan3(int i){
    		return i > 3;
    	}
    	
    	public static boolean isLessThan11(int i){
    		return i < 11;
    	}
    

    If you are surprised with the double colon (::) operator, it’s introduced in Java 8 and used for method references. Java Compiler takes care of mapping the arguments to the called method. It’s short form of lambda expressions i -> isGreaterThan3(i) or i -> NumberTest.isGreaterThan3(i).

Lambda Expression Examples

Below I am providing some code snippets for lambda expressions with small comments explaining them.


() -> {}                     // No parameters; void result

() -> 42                     // No parameters, expression body
() -> null                   // No parameters, expression body
() -> { return 42; }         // No parameters, block body with return
() -> { System.gc(); }       // No parameters, void block body

// Complex block body with multiple returns
() -> {
  if (true) return 10;
  else {
    int result = 15;
    for (int i = 1; i < 10; i++)
      result *= i;
    return result;
  }
}                          

(int x) -> x+1             // Single declared-type argument
(int x) -> { return x+1; } // same as above
(x) -> x+1                 // Single inferred-type argument, same as below
x -> x+1                   // Parenthesis optional for single inferred-type case

(String s) -> s.length()   // Single declared-type argument
(Thread t) -> { t.start(); } // Single declared-type argument
s -> s.length()              // Single inferred-type argument
t -> { t.start(); }          // Single inferred-type argument

(int x, int y) -> x+y      // Multiple declared-type parameters
(x,y) -> x+y               // Multiple inferred-type parameters
(x, final y) -> x+y        // Illegal: can't modify inferred-type parameters
(x, int y) -> x+y          // Illegal: can't mix inferred and declared types

Method and Constructor References

A method reference is used to refer to a method without invoking it; a constructor reference is similarly used to refer to a constructor without creating a new instance of the named class or array type.

Examples of method and constructor references:


System::getProperty
System.out::println
"abc"::length
ArrayList::new
int[]::new

That’s all for Java 8 Functional Interfaces and Lambda Expression Tutorial. I would strongly suggest to look into using it because this syntax is new to Java and it will take some time to grasp it.

You should also check out Java 8 Features to learn about all the improvements and changes in Java 8 release.

Comments

  1. Omonge says:

    This is awesome.I am really enjoying it .Can i be able to have all this offline on my machine

  2. zahra darvishian says:

    First thanks for your clear and great tutorial; just a thing that should be corrected:
    in code snippet for functional interface, as the codes are in Java, it’s better to write “implements” instead of “extends” in bellow one:

    interface X { Iterable m(Iterable arg); }
    interface Y { Iterable m(Iterable arg); }
    interface Z extends X, Y {}

    Thanks.

    1. zahra says:

      I thought Z, is a class, not an interface that was my fault.
      thanks again.

  3. Ruchi Gupta says:

    interface X { int m(Iterable arg); }
    interface Y { int m(Iterable arg); }
    interface Z extends X, Y {}
    // Functional: two methods, but they have the same signature

    interface X { Iterable m(Iterable arg); }
    interface Y { Iterable m(Iterable arg); }
    interface Z extends X, Y {}
    // Functional: Y.m is a subsignature & return-type-substitutable

    interface X { int m(Iterable arg); }
    interface Y { int m(Iterable arg); }
    interface Z extends X, Y {}
    // Not functional: No method has a subsignature of all abstract methods

    interface X { int m(Iterable arg, Class c); }
    interface Y { int m(Iterable arg, Class c); }
    interface Z extends X, Y {}
    // Not functional: No method has a subsignature of all abstract methods

    interface X { long m(); }
    interface Y { int m(); }
    interface Z extends X, Y {}
    // Compiler error: no method is return type substitutable

    interface Foo { void m(T arg); }
    interface Bar { void m(T arg); }
    interface FooBar extends Foo, Bar {}

    Can somebody please elaborate these examples, not able to understand.

  4. subbu says:

    Nice. Simplified presentation of Lambdas and Functional Interfaces.

  5. zone says:

    Please change the css style of some of the syntax as it is not rendered properly in browser. the text is masked with black background.

    Ex :@FunctionalInterface in this page is not displayed at all

    1. Pankaj says:

      The background is black but the text is white and readable. If possible, can you share a snapshot so that I can see exact issue you are facing?

      Also, could you please clear your cookie and cache? It might be an issue because of cached CSS file.

  6. Srilekha says:

    Is it not mandatory to add abstract keyword in method declaration as we did in previous versions of java interfaces before java 8 in interfaces concept?
    Once if we declare interface as functional interface,is it not required to add abstract during method declaration
    Eg. Public abstract void m1();

    1. Harsha says:

      Thanks for adding this comment. It’s helpful.

  7. Sandip says:

    Thanks Pankaj,
    Nice and very simplified presentation of Lambdas and Functional Interfaces.
    Please keep contributing.

  8. Mohammed Farooq says:

    Simple yet very effective explanation.

  9. siva says:

    interface X { int m(Iterable arg); }
    interface Y { int m(Iterable arg); }
    interface Z extends X, Y {}

    this will not compile…

    1. Haldhar says:

      above code compile successfully for me.

  10. Atul Sharma says:

    Hi ALl,

    I have created a program taking blog example and try to find out the execution time of the method with and without Lamda operation.

    public class IsPrimeNumber {

    public static void main(String [] argd) {
    System.out.println(Calendar.getInstance().getTimeInMillis());
    System.out.println(IsPrimeNumber.isPrimeLamda(99));
    System.out.println(Calendar.getInstance().getTimeInMillis());

    System.out.println(Calendar.getInstance().getTimeInMillis());
    System.out.println(IsPrimeNumber.isPrime(99));
    System.out.println(Calendar.getInstance().getTimeInMillis());
    }

    private static boolean isPrime(int number) {
    if(number < 2) return false;
    for(int i=2; i 1
    && IntStream.range(2, number).noneMatch(
    index -> number % index == 0);
    }

    }

    But in the result, the time taken by the standard method is less than the Lamda operation. method.

    In actual it increases the execution time of the program

    Thanks
    Atul Sharma

    1. Haldhar says:

      Lamda operation takes more time then normal method.

  11. NS says:

    I don’t think, this is a good post, as nothing is understandable.

    1. Pradeep says:

      Just because you didn’t understand doesn’t mean it’s not good. Try out the sample code in your IDE.. May be you will understand better

  12. sawai says:

    I am new in Functional Interface and today i am learning from few of tutorial sites. I have a question plz provide your suggestions and guide me.

    Below mentioned code have an question for me.

    @FunctionalInterface
    interface Demo {
    Object clone(); // protected
    //int hashCode(); // public
    //boolean equals(Object c); // public
    //public void wait(); // final so we cannot override this one.
    }

    > Object class is parent for all java classes.
    > here wait() method says not overrided bcoz this one is final. So its mean Demo interface also child of Object class (in general terms).

    > @FunctionalInterface means interface with exact one method declaration.

    > Question: So, Now code is working when **Object clone();** method is not commented. So means this method is declared in interface Demo. But when we click on its implementation we move on Object class’s clone() method.
    When we comment clone() method and un-comment equals() method, then we get compile time error, interface is not FunctionalInterface. Why ?????? and why its functional interface with clone() method.

    Please don’t say clone() is protected, what’s the matter if clone is protected in Object class. Please explain for me.

    Thanks, sawai

  13. nimisha says:

    I didnt get how you are marking interfaces as funcyional or non functional on basis of signature. Please explain.

  14. Vipul says:

    What is numberTest here ??

    return numbers.stream()
    .filter(NumberTest::isOdd) //Predicate is functional interface and
    .filter(NumberTest::isGreaterThan3) // we are using lambdas to initialize it
    .filter(NumberTest::isLessThan11) // rather than anonymous inner classes
    .max(Comparator.naturalOrder())
    .map(i -> i * i)
    .get();

    1. Ravi says:

      NumberTest is the name of the class containing the static methods which are referenced in the lambda expression.

  15. Hitendra Kumar says:

    Good to see you here ! You remember me?

  16. Sam says:

    Nice tutorial. Just a little bug in your code for prime numbers:


    //Declarative approach
    private static boolean isPrime(int number) {
    return number > 1
    && IntStream.range(2, number - 1).noneMatch(
    index -> number % index == 0);
    }

    I think you mean “range(2, number)” since the end is exklusive 🙂

    1. Pankaj says:

      Hi Sam,

      Thanks for pointing it out, i have corrected it.

  17. Prashanth R says:

    Nice Article.

  18. JHElp says:

    Again, this article convince me to not use Lambda expression.
    1) Shorter code (in number of lines) don’t means better code
    2) Anonymous class , if you are a good Java developer, you never use them
    3) For parlellism, a good usage of threads is better than this. Because here the exemple show an ideal case, each task are independant, but if you need synchronize some result in future, you have to write every things. So why not directly write with good thread management ?
    4) For pass method as argument is useless, a good management interface and abstract fit.
    5) Its not seems very evolutive, if you need change something (You know in real life, every code need to change), you have to change in several place. Not very connient.

    Conclusion :
    It may be use for test, but for a real code, its not a good idea. It still don’t understand why lambda exists. Is it for bad developer to be able developer worser ?

    1. fedeb says:

      This is a small step Java is making toward the functional paradigm, so take it like that. Less code with lambda sometimes means more readable code, of course if you make everything a lambda it simply is bad. We hope Java makes more functional things, like pattern matching

    2. Renan says:

      2) Anonymous class , if you are a good Java developer, you never use them
      – Why exactly is that? Anonymous classes exist everywhere, particularly in Swing, and in generic patterns. Your argument might be to always declare full classes is one of Java’s greatest failings – verbosity. You almost always have to declare everything. The language is making YOU work, the language is not working for you.

      3) For parlellism, a good usage of threads is better than this. Because here the exemple show an ideal case, each task are independant, but if you need synchronize some result in future, you have to write every things. So why not directly write with good thread management ?
      – You just elaborated WHY this pattern exists – because some thread usage falls into the ‘ideal’ basket, and they don’t require synchronization between threads. If I don’t need synchronization then why do I have to bother with thread management? You are advocating for unnecessary work due to Java’s traditional verbose structure.

      4) For pass method as argument is useless, a good management interface and abstract fit.
      well this just doesn’t make any sense

      Lambdas isn’t for every scenario, just like generics and every major Java change in the past decade. It has its uses, and if you’ve worked with enough Java as I have you’d understand where Lambdas shine. The ability to take advantage of parallelism in simple cases like collection processing using 3-4 lines of code is a god-send! Not sure why any sane Java programmer would look at that and say “useless”.

    3. Robert says:

      I think you didn’t understand anything from Lambda expression.

      Just read some more articles Carefully!

      “Anonymous class , if you are a good Java developer, you never use them” ???? You need to learn Java basics. Take a look at https://www.amazon.com/Java-Dummies-Computers-Barry-Burd/dp/1119175690

  19. Madhumita Bhattacharjee says:

    Thanks for providing this article. Really informative.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages