Java 8 Lambda Expression Basics

This articles helps you in understanding and using Java 8’s Lambda expression in effective manner.

To avoid detailing out mere theoretical concepts which are available in plenty in the internet, I have approached this in a more cookbook style way. There are 3 questions with accompanying answers.

What is Lambda expression and why should I care?

While designing a solution following OOP approach, nouns are mapped to Classes. Classes have attributes and behaviors (functions that the class can perform). Therefore functions are only accessible within the context of a Class that contains it.

In Java either the class needs to be instantiated to create an object of it. Thereafter the instance method / function can be invoked on the object reference. If the function is static there is no need of object instantiation. It can be directly invoked using class reference.

What if we are only concerned about the functions. In OO world, to be able to use a function/behavior we need to have an adjoining class.

For an example, lets think of greeting in various acts, as a function. Following interface declares the same.

public interface ActOfGreeting {
	
	void perform();

}

Without using an anonymous inner class or a concrete class it is not possible to use this behavior.

So lets implement the interface, using a class called HumbleAcOfGreeting as shown in following snippet

public class HumbleActOfGreeting implements ActOfGreeting {

	@Override
	public void perform() {
		System.out.println("hello world :-)");

	}

} 

Now we can always instantiate an object of HumbleActOfGreeting and use the method implementation and though we are only concerned about the function implementation we need to have a full blown class to act as function container.

This is the problem Lambda tries to address. Lambda enables you to author a function that does not belong to any class. A lambda expression can be passed around as if it was an object and executed on demand. This is clearly the first step towards treating a function as first class citizen, the very basis of functional programming.

In summary following are key benefits of writing code using Lambda expression

  1. enables functional programming
  2. helps in writing more readable and concise code
  3. author better API and libraries
  4. enables parallel processing

As you see, would not it be amazing if you can directly author function that contains business logic, and reuse; all without requiring to have a parent class? If your answer is yes, proceed to the next section.

**How to construct/use a lambda expression? **

Lets start where we left in the previous question. The class that uses act of greeting function have following code

public class Greeter {

	public void greet(ActOfGreeting greeting) {
		greeting.perform();
	}

	public static void main(String[] args) {

		Greeter greeter = new Greeter();
		ActOfGreeting actOfGreeting = new HumbleActOfGreeting();
		greeter.greet(actOfGreeting);

	}
}

The function that we are concerned about is following

public void perform() {
		System.out.println("hello world :-)");
}

Lets construct a Lambda expression from this. Lambda expression, by promise should be a standalone function which can be assigned to a variable. The variable can be passed away as argument and used as and when necessary.

With that, it should look like following (not a compliable Java code )

SomeType myLambdaVariable = public void perform(){ SOP("hello world :-)");}

step-1

Access modifiers are only relevant within the context of a Class. As Lambda expression does not belong to a Class there is no point of having access modifier. After removing access modifier above expression will look like following

SomeType myLambdaVariable = void perform(){ SOP("hello world :-)");}

step-2

Compiler is able to derive judging from method implementation that the return type is void, hence explicit return type is not required as well. With that change the expression become

SomeType myLambdaVariable = perform(){ SOP("hello world :-)");}

step-3

As the function gets assigned to a variable (which is used thereafter) there is no point in having name. After removing it the expression becomes

SomeType myLambdaVariable = (){ SOP("hello world :-)");}

step-4

Finally, by placing -> operator, between () and {} above, RHS represents a perfectly valid Lambda expression.

SomeType myLambdaVariable = () -> { SOP("hello world :-)");}

The LHS of the expression needs a bit more discussion about Functional Interface, which we will do next.

In case there are input arguments

In above scenario, perform method takes no argument. What if the method takes a String argument and have following signature

public interface ActOfGreeting {
  void perform(String message);
}

In this case, the Lambda expression will require to be written as following

SomeType myLambdaVariable = (String message) -> { SOP("hello world :-) : " + message);}

As you see, the input argument with fully qualified type is mentioned inside () brackets.

Following are few more examples in similar line

myFunc = (int i) -> {return i + 2;};
myFunc = (int i) ->  i + 2;
myFunc = (int i, int j) ->  i + j;
myFunc = (int i, int j) -> {if (j==0) return 0 else return i/j;}

What is a functional interface

A functional interface is an interface that has exactly one abstract method. Following is an example for the same

public interface ActOfGreeting {
  void perform(String message);
}

When we construct a Lambda expression, there has to be a target functional interface. A Lambda expression, therefore can be assigned to the functional interface it implements, as shown in following updated code snippet

ActOfGreeting greeting = () -> {SOP("hello world :-)");};

Here after, greeting variable can be passed to any other methods/API which takes ActOfGreeting as input.

Note in case an existing functional interface have more than one abstract method, it stops being a functional interface any more, and compilation fails. However the interface can have default method.

Annotating an interface as @FunctionalInterface would raise compile time error if the interface is attempted to be changed so as to contain more that one abstract method.

Following are few example highlighting the concept

Functional Interface Lambda Expression
public interface IncreaseByTwo{ int increaseByTwo(int i);} (int i) -> {return i + 2;};
public interface Add{ int add(int i, int j);} (i,j) -> {return i+j;}
public interface SafeDivide {int safeDivide(int i, int j);} (int i, int j) -> {if (j==0) return 0 else return i/j;}

Configuring JDK 8 on Windows

This post details out steps to configure JDK 8 on Windows without running .exe file

Problem

The product that we are developing for some time now, is built and shipped based on Java 7. Now that Java 7 has officially reached end of life, we wanted to move on using Java 8, instead.

Apart from this, we were sold to loads of great stuff that Java 8 brings onto the table.

We wanted to move cautiously, refactoring our product one module at a time to avoid unwanted side effect. Even before we struck any architectural or design challenges we had to satisfy a basic requirement. In our shop Windows professional version is being used on Developer’s laptop. They already have Java 7 installed and configured on their machine.

We wanted to configure Java 8 so that it can co - exist with Java 7, without requiring to run official jdk-8uXYZ-windows-x64.exe that one can download from Oracle’s official site, where XYZ indicates respective update id. This was necessary as we did not want installer to alter Windows registry entries (that has already been made by earlier by JDK 7 installer).

How can we solve this issue ??

Solution

The solution looks more like a hack but served the purpose well.

Steps
  • Download JDK 8 from Oracle’s official site. For us it is jdk-8u121-windows-x64.exe
  • Download and install 7-Zip
  • Copy the executable on a folder
  • Right - click on the execution and from 7-Zip menu select and click Extract Here
  • Once extraction completes, you should be able to see following files and a folder named .rsc in current directory
    • .data
    • .pdata
    • .rdata
    • .reloc
    • .rsrc (this one is a directory)
    • .text
    • CERTIFICATE
  • (For x64 Windows machine) navigate to .rsrc\1033\JAVA_CAB10 folder. You should be able to locate a file with name 111 here
  • Right - click on the execution and from 7-Zip menu select and click Extract Here
  • Once extraction completes, you should be able to see tools.zip file
  • Copy tools.zip into a target folder and extract it there. Lets assume this folder as D:/JavaJDK/
  • As a final step, we need to unpack few files which are packed with pack200. We do that by executing this script in a console window inside the root of the JDK directory (i.e. “D:/JavaJDK/”):
    • for /R %f in (.\*.pack) do @"%cd%\bin\unpack200" -r -v -l "" "%f" "%~pf%~nf.jar"

and thereafter D:/JavaJDK/ can serve as JAVA_HOME for Jdk 8 … problem solved :-)