JAVA 8 Lambda Expression as Interface Type- Functional Programming in JAVA 8- Part 2

Java

JAVA 8 Lambda Expression as Interface Type- Functional Programming in JAVA 8- Part 2

Before reading this post kindly go through part 1 of this post to understand lambda expression.

http://jkoder.com/understanding-java-8-lambda-expression-functional-programming-in-java-8-part-1/

It’s time to uncover the type of lambda expression and the execution of lambda expression. Here’s the code that we have been looking in the part-1 post.

public interface Greeting {
	public void perform();
}

public class HelloWorldGreeting implements Greeting {

	@Override
	public void perform() {
		System.out.println("Hello World!");
	}
}

public class Greeter {

	public void greet(Greeting greeting){
		greeting.perform();
	}
	
	public static void main(String[] args) {
		Greeter greeter=new Greeter();
		Greeting helloWorldGreeting=new HelloWorldGreeting();
                greeter.greet(helloWorldGreeting);
	}
}

Output:- Hello World!

Here we have greet method takes the implementation of Greeting interface and execute the perform method which just prints “Hello World!” to console. Also we have the implementation of Greeting interface. Now we want to change the greet method and make it to accept lambda expression as well. We have to fit below code in our picture.

	myLambdaFunction = () -> System.out.println("Hello World!");

Now the question that we were troubling with is, what’s the type of myLambdaFunction variable? As JAVA is strongly types language so there has to be some type for our variable. Is there a type FunctionType in JAVA 8, NO. JAVA language designers didn’t really do this, they actually used the present Interface system for declaring lambda expressions. So, here is what we gonna do for declaring lambda expression type in JAVA. First, create a new Interface in order to declare a lambda expression. Second, create one method in the interface which has the exact same signature as the lambda expression has. In our case there is no argument & it returns a void.

        MyLambda myLambdaFunction = () -> System.out.println("Hello World!");

	interface MyLambda{
	        public void foo();
        }

So you can use MyLambda interface as the type of of the lambda function, and this interface used for declaring lambda expression is called Functional Interface. This Functional interface is used for type checking. JAVA looks this interface and it’s method and says I have all the information that I need to figure out what the lambda expression is. This Functional interface is a guarantee to JAVA compiler that it will have only one method whose signature matches with that of lambda expression. Yes, you heard me correct, Functional interface should have only one method. JAVA has reused the concept of interface to declare a lambda expression.

Let’s do one more example, let’s write add function that adds 2 integers.

        MyLambda myLambdaFunction = () -> System.out.println("Hello World!");
        MyAdd addFunction = (int a, int b) -> a+b;

	interface MyLambda{
	        public void foo();
        }

	interface MyAdd{
	        public int add(int x, int y);
        }

Voila, it’s done. All that matters is the name of the name of the interface should be same as that of variable & method signature of interface should be same as signature of lambda expression. If name of interface & signature is all that matters then we can use Greeting interface that already has a valid function signature.

        Greeting lambdaGreeting = () -> System.out.println("Hello World!");
        public interface Greeting {
	      public void perform();
        }

So, what happens if you add one more method in the interface which you used for declaring lambda expression(Functional interface), there will be an error in the functional expression declaration, “The target type of this expression must be a functional interface.”. Idea is compiler is confused as there are 2 methods, compiler is confused to do type checking with the function of interface.

The implicit rule here is, when you are using an interface to declare a lambda expression that interface should have only one method & that method should be having same signature as the lambda expression. Now the compiler will be happy again.

	Greeting helloWorldGreeting = new HelloWorldGreeting();
        Greeting lambdaGreeting = () -> System.out.println("Hello World!");

I know what question is surrounding your mind, what’s the difference helloWorldGreeting instance variable the implements Greeting interface and lambdaGreeting lambda expression variable which sort of implements Greeting interface. Let’s talk about the difference between helloWorldGreeting and lambdaGreeting. Both variables are of type Greeting interface.

helloWorldGreeting is an instance of Greeting interface which holds the object of custom class HelloWorldGreeting that implements Greeting interface, whereas lambdaGreeting holds a lambda expression whose type is Greeting interface that has a method whose signature matches with that of lambda expression. What happens we call method on helloWorldGreeting and lambdaGreeting.

	helloWorldGreeting.perform();
        lambdaGreeting.perform();

Well both of them gives same output i.e. “Hello World!”. And this is how you execute lambda expression. By calling the interface method on it, just as if it were an instance of a class. Lambda expression just behaves like an implementation of the Greeting interface. So what’s the difference, lambda expression is actually a way of implementing the interface by just implementing the function and not implementing the class. lambdaGreeting is a Lambda expression of type interface. helloWorldGreeting implements the Greeting interface in a new class and we provided the logic in that class. For lambdaGreeting we are not creating a class, we are just creating a lambda expression inline & getting assigned to type Greeting. It’s almost as if we have created an implementation of the Greeting interface.

However, for helloWorldGreeting it’s not necessary to create a brand new class, you can do it via Anonymous inner class.

	Greeting innerClassGreeting = new Greeting(){
               public void perform(){
                   System.out.println("Hello World!");
               }
        };

Inline instance of Greeting interface with the implementation being inline. This is Anonymous inner class as the class is defined inside another class & doesn’t have a name. Till now we have 3 types of implementations:-

  • implementation as a Class
  • implementation as Lambda expression
  • implementation as Anonymous inner class

There are many online tutorials which claim that Lambda expression is shortcut for Anonymous inner class implementation. You can say so in a way, but they both are different. Think lambda expression that implements only interface method and the interface is just used for type of lambda expression variable. Now let’s pass the respective variables of Greeting interface type.

public interface Greeting {
	public void perform();
}

public class HelloWorldGreeting implements Greeting {

	@Override
	public void perform() {
		System.out.println("Hello World!");
	}
}

public class Greeter {

	public void greet(Greeting greeting){
		greeting.perform();
	}
	
	public static void main(String[] args) {
		Greeter greeter=new Greeter();
		Greeting helloWorldGreeting=new HelloWorldGreeting();
 
                Greeting lambdaGreeting = () -> System.out.println("Hello World!");

	        Greeting innerClassGreeting = new Greeting(){
                    public void perform(){
                        System.out.println("Hello World!");
                    }
                };
                
                greeter.greet(helloWorldGreeting);
                greeter.greet(lambdaGreeting);
                greeter.greet(innerClassGreeting);
	}
}

Output:-
Hello World!
Hello World!
Hello World!

About Anoop Kumar Rai