Core Java

Java 8 Anonymous Function Example

1. Introduction

Java is an object Oriented Programming Language, and as such concepts like Encapsulation and Abstraction sits at the heart of it. However, since Java is a bit-too-much Object Oriented at its genome structure, that often times than not, it adds a lot of verbosity and boiler plate to its language constructs.
 
 
 
 
 
 

 
Even simple, trivial requirement of creating an API for adding two integer number has to go through a complete set of boiler plate, for instance: (i) we need to create a class, (ii) and expose interface methods from which would accept two numbers, adds them and returns the output.

Simple class to add two numbers

public class Adder{
   public int addNumbers (int a, int b){
       return a+b;
   }
}

Even the clients which needs to use this Adder has to go through a complete process:
How client would use Adder class

    Adder adder = new Adder();
    int sum = adder.addNumbers(1, 2);

And so it is clear that there is quite a bit of verbosity and boiler plate already in this approach. Thus, in this post we would see how we can reduce the boiler plate for such tasks and the various options available for doing so.

2. Functional Interfaces

Let us say, in our project we recognize all single task APIs; that is, those APIs which have one and only task to handle. Like our Adder class which has only one duty: to add two numbers and provide the output. So, we recognize all such tasks and expose them over a Java Interface:

A Functional Interface

   public interface AdderInterface {
      int addNumbers(int a, int b);
   }

And later an implementing class like Adder can implement it. However, there is a special place for such single tasked-interfaces in Java, and their presence has become even more prominent ever since JDK 8 was released. We would soon get to them but it is interesting to note that even JDK has instances of single-tasked interfaces, the java.lang.Runnable Interface, for instance.

Such interfaces are called functional interfaces. Functional interfaces are interfaces with one and only one abstract method in it. And this abstract method would define the ‘functionality’ of this interface. Having said that, a Functional interface, may has other non-abstract methods – the default methods declared with the default key word. These default methods provide the default implementations to the interface in case the implementing class does not provide any!

Now there are two ways of implementing a functional interface. First would be to create a separate class, like Adder, which would implement the functional interface; or, we could implement the interface anonymously!

3. Anonymous Classes

Remember we pointed out the verbosity issue; to avoid that we might employ an anonymous implementation of the interface.

An anonymous implementation of Functional Interface

AdderInterface addrInterface = new AdderInterface (){
                                  public int addNumbers (int a, int b){
                                     return a+b;
                                  }
                               };

Now this addrInterface, which has an anonymous implementation of the original AdderInterface, can be passed around as if it was a regular, named implementation of the AdderInterface interface! Note that in the above implementation of AdderInterface interface we did not create any concrete class implementing the interface. In doing so, we have already reduced fair amount of boiler plate and verbosity.

However, it is not just the reduced boiler plate and verbosity that is gained, there are other subtle nuances to be observed. Consider the anonymous implementation once again, however, this time encapsulated in a class which has its own member variable, say outer and the anonymous implementation would also has a state – inner:

Accessing different members from anonymous implementation

class Encapsulator{
  int outer = 50;
  AdderInterface addrInterface = new AdderInterface (){
                                  int inner = 30;
                                  public int addNumbers (int a, int b){
                                     int in = this.inner; //inner accessible!
                                     /*this.outer*/ //outer not accessible!
                                     Encapsulator.this.outer //outer accessible now!
                                     return a+b;
                                  }
                               };
} 

Notice that the instance variable inner is accessible inside the anonymous implementation of addNumbers(...)method; however, outer variable, which is an instance variable of the encapsulating class is not accessible just like that; to access outer inside the anonymous implementation, we would have to use the following construct: Encapsulator.this.outer

In the next section we would see, how boiler plate and verbosity can be further reduced by employing Lambda Expressions!

4. Lambda Expression

Although anonymous implementation did reduce verbosity to some extend, but there is still a lot of space of reduction; we still have quite a bit of formalism and ceremony in the code. This could be further reduced by employing Lambda Expression.

4.1 What is Lambda Expression

Lambda expression is just an expression/statement or series of expressions/statements. Now if statement/s make you think about methods, then obviously yes, lambda expressions are methods, albeit, anonymous. Thus, I may say that lambda expressions are nameless methods. And so you would find lambdas taking in parameters to work upon and returning values as well.

However it should be immediately stated here that lambda expression – or blocks of code (there can be just a single statement as well!) – do not exist in and of themselves. That is to say, lambda expressions do not exist independently; they come in conjunction with Functional Interfaces. And so we define for you what a Functional interface is. But before we do that, note that Lambda expressions without any Functional interface is an absurd notion.

4.2 How to express Functional Interfaces with Lambda Expressions

It is extremely flexible to translate or provide an implementation to a Functional Interface via Lambda Expression. All we need is to keep an eye on the input parameter list and the return type of the. And so the Lambda implementation of addNumbers(...) would be:

Lambda Expression Structure

 (int a, int b) -> return a+b;

And that is it, we are done!

Furthermore, we can even assign this lambda expression to the functional interface type, as follows:
Assigning Lambda Expression to a Functional Interface type

AdderInterface ai = (a, b)-> return a+b;

Note that we dropped types for parameters a and b, since Java type system would be able to infer the type(s) at compile time. Furthermore, we can pass around the lambda expression contained in ai variable between methods!

4.3 Subtleties with Lambda Expressions

Recall we analyzed capturing instance member variables from the containing class (of the anonymous implementation) and the member variables declared within the anonymous class itself. With Lambda Expressions, though, the instance members from the containing/outer class can be directly accessed via the this operator:
Accessing member variable from enclosing class in a Lambda Expression

class Encapsulator{
  int outer = 50;
  AdderInterface addrInterface = (a, b) -> {
                                             int var = this.outer;  //accessible directly
                                                                    //No need for Encapsulator.this.outer
                                             return a+b;
                                     };
}

This establishes that the lambda expression has the implicit this reference of the containing class in it.

5. Conclusion

Until before JDK8, anonymous implementations of interfaces were quite handy. Java developers were relaxed of creating separate class implementing the interface and then to use it. However, as we saw, even with anonymous class implementation there were fair amount of ceremony, verbosity and boiler plate involved; using lambda expression reduces all of it. Lambda Expression, as we saw, is sweet, small, terse and very compact! Hence forth, wherever you find a suitable opportunity to employ Lambda Expression in place of anonymous implementation, employ it!

Nawazish Khan

I am Nawazish, graduated in Electrical Engineering, in 2007. I work as a Senior Software Engineer with GlobalLogic India Ltd (Banglore) in the Telecom/Surveillance domain. A Java Community Process (JCP) member with an unconditional love (platform, technology, language, environment etc does not matter) for computer programming. Extremely interested programming multi-threaded applications, IoT devices (on top of JavaME) and application containers. The latest language of interest being Google Go; and Neo4j as the NoSQL Graph Database solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button