Templates by BIGtheme NET

JAVA 8 Feature Lambda expressions

In this article, I will show you how lambda expressions can be used in projects and
how these expressions are help to do clean coding. How to role out our own functions,
and call those with lambda expressions.
How these lambda expressions are differ from closures.

Is lambda expressions are completely new feature in Java 8? – Answer is No

What is Lambda expressions?
Lambda is a block of code that can be passed as an argument to a function call.
Lambda expressions in Java 8 are a succinct syntax for expressing anonymous functions.
They are a syntactic improvement over anonymous inner classes in Java,
but are function quite similar. If we see the syntax, it is quite simple.
(arguments) -> { function body }

Here, arguments – is the numbers of arguments with or with out data types.
function body – is the actual implementation of the function/ method.

Examples :
(double x) -> x + 2
(x) -> x + 2
x -> x + 2

We can declare constant lambda also,
(String s) -> {System.out.println(“Lamda expressions examples: %s” + s); }
() -> 143

LambdaExpressionsExampl.java

package com.devjavasource.java8.lambdaexpressions;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class LambdaExpressionsExample {

	public static void main(String[] args) {		
		// Anonymous add function
		SimpleInterface1 obj1 = new SimpleInterface1() {
			@Override
			public void method1() {
				System.out.println("Hello JAVA 8 Anonymous example!");
			}
		};
		// Lambda Add function
		SimpleInterface1 obj2 = () -> System.out.println("Hello JAVA 8 Lambda example!\n");
		// Run anonymous & lambda expression function
		obj1.method1();		
		obj2.method1();
		
		//Simple lambda expression with single method parameter
		SimpleInterface2 obj3 = (x) -> { 
				x = x + 2; 
				System.out.println("Incremented value is: " + x ); 
			};		
		obj3.method2(4);			
		obj3.method2(7);
		
		//How to manipulate collections as parameter to lambda expression
		Bank sbi = new Bank("SBI", "SBI_CODE", 11);
		Bank icici = new Bank("ICICI", "ICICI_CODE", 22);
		Bank hdfc = new Bank("HDFC", "HDFC_CODE", 33);
		// Create a collection - List
		List<Bank> banks = new ArrayList<>();
		banks.add(sbi);
		banks.add(icici);
		banks.add(hdfc);		
		// Create lambda expression to get only "SBI" banks from the list.
		BankInterface specificBankObj = (bankList, bankName) -> {
			printlBankDetails( bankList.stream()
					                   .filter( bank -> bank.getBankName().equals(bankName) // to filter only sbi banks
					          ));
		};
		System.out.println("\n************LIST ALL SBI BANKS IN LIST**********");
		specificBankObj.getBanks(banks, "SBI"); // To list only SBI banks
		System.out.println("************LIST ALL ICICI BANKS IN LIST**********");
		specificBankObj.getBanks(banks, "ICICI"); // To list only ICICI banks
		System.out.println("************LIST ALL HDFC BANKS IN LIST**********");
		specificBankObj.getBanks(banks, "HDFC"); // To list only HDFC banks
	}
	
	public interface BankInterface {
		public abstract void getBanks(final List<Bank> inBankList, final String inBankName );
	}

	public interface SimpleInterface1 {	    
	    public abstract void method1();
	}
	
	public interface SimpleInterface2 {	    
	    public abstract void method2(int x);
	}
	
	public static class Bank {
		private String bankName;
		private String bankCode;
		private int ifscCode;

		public Bank(final String inBankName, final String inBankCode,
				final int inIfscCode) {
			bankName = inBankName;
			bankCode = inBankCode;
			ifscCode = inIfscCode;
		}

		public String getBankName() {
			return bankName;
		}

		public int getIfscCode() {
			return ifscCode;
		}
	}
	
	private static void printlBankDetails(final Stream<Bank> inBankStream) {
		inBankStream.forEach(each -> {
			System.out.println("Bank Name : " + each.getBankName());
			System.out.println("Bank IFSI Code : " + each.getIfscCode());
		});
	}
}

Select “Run As” -> “Java Application”
Out Put:

Hello JAVA 8 Anonymous example!
Hello JAVA 8 Lambda example!

Incremented value is: 6
Incremented value is: 9

************LIST ALL SBI BANKS IN LIST**********
Bank Name : SBI
Bank IFSI Code : 11
************LIST ALL ICICI BANKS IN LIST**********
Bank Name : ICICI
Bank IFSI Code : 22
************LIST ALL HDFC BANKS IN LIST**********
Bank Name : HDFC
Bank IFSI Code : 33

Some lambda examples implementing Java classes often implemented via inner classes :

1) java.lang.Runnable

// java.lang.Runnable
new Thread(() -> {
	connect();
	fetchData();
        }).start();

2) java.util.Comparator

Comparator<Bank> comparator = (b1, b2) -> b1.getIfscCode()
                                    .compareTo(b2.getIfscCode());

3) java.io.FileFilter

(File f) -> f.getName().endsWith(".html");

4) java.util.concurrent.Callable

 Callable<String> c = () -> "Cllable example of lambda expressions!"; 

5) java.beans.PropertyChangeListener
6) java.security.PrivilegedAction

 PrivilegedAction<String> a = 
                         () -> "PriviligedAction example of lambda expressions!"; 

LambdaExpressionsImpInnerClassesInJava.java

package com.devjavasource.java8.lambdaexpressions;

import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.stream.Stream;

public class LambdaExpressionsImpInnerClassesInJava {

	public static void main(String[] args) {
		// java.lang.Runnable
		new Thread(() -> {
			connect();
			fetchData();
		}).start();

		// java.util.concurrent.Callable
		Callable<String> c = () -> "Cllable example of lambda expressions!";

		// java.security.PrivilegedAction
		PrivilegedAction<String> a = () -> "PriviligedAction example of lambda expressions!";

		// java.util.Comparator
		Comparator<Bank> comparator = (b1, b2) -> b1.getIfscCode().compareTo(
				b2.getIfscCode());

		// How to manipulate collections as parameter to lambda expression
		Bank sbi = new Bank("SBI", new Double(11));
		Bank icici = new Bank("ICICI", new Double(33));
		Bank hdfc = new Bank("HDFC", new Double(22));
		// Create a collection - List
		List<Bank> banks = new ArrayList<>();
		banks.add(sbi);
		banks.add(icici);
		banks.add(hdfc);

		banks.sort(comparator);
		printlBankDetails(banks.stream());
		banks.sort(comparator.reversed());
		printlBankDetails(banks.stream());
	}

	private static void printlBankDetails(final Stream<Bank> inBankStream) {
		inBankStream.forEach(each -> {
			System.out.println("Bank Name : " + each.getBankName());
			System.out.println("Bank IFSI Code : " + each.getIfscCode());
		});
	}

	private static void connect() {
		System.out.println("********Connected************");
	}

	private static void fetchData() {
		System.out.println("****FETCH THE DATA FROM OUTSIDE SOURCE**");
	}

	public static class Bank {
		private String bankName;
		private Double ifscCode;

		public Bank(final String inBankName, final Double inIfscCode) {
			ifscCode = inIfscCode;
			bankName = inBankName;
		}

		public Double getIfscCode() {
			return ifscCode;
		}

		public String getBankName() {
			return bankName;
		}
	}
}

Select “Run As” -> “Java Application”

Out Put:

********Connected************
****FETCH THE DATA FROM OUTSIDE SOURCE**
Bank Name : SBI
Bank IFSI Code : 11.0
Bank Name : HDFC
Bank IFSI Code : 22.0
Bank Name : ICICI
Bank IFSI Code : 33.0
Bank Name : ICICI
Bank IFSI Code : 33.0
Bank Name : HDFC
Bank IFSI Code : 22.0
Bank Name : SBI
Bank IFSI Code : 11.0

Why Lambda?

We all know Java Language is an object oriented programming language.
But sometimes we want to pass some code to a method instead of an object.
To make this happen we are implementing Callbacks.
This leads us to develop verbose code and it feels not like to be well supported by Java.
An additional use case is dealing with groups of data. Sometimes it is necessary
to execute a specific algorithm to a group of data.
Functional programming langues support things like “forAllDo”.
In Java you need to implement that by yourself or have to use some utility classes from third party libraries.
This might be verbose and creepy.

How to role out our own functions?

Its possible to define interfaces (or classes) and implement them using lambdas in Java.
This is useful when you want to package up a function and treat it the way you might treat any variable.
This functionality is generally implemented in Java using anonymous inner classes.

In Java 8, lambda functions replace anonymous inner functions and are syntactically cleaner and more intuitive.

Three simple steps to implement,
1) Define an interface with one function.

static interface BankOperations<T> {
	public T operation(Bank sbi1, List<Bank> banks);
}

2) Create some lambda functions. Here in this example we are creating add and delete lambda functions
to add new bank details and delete existing bank from bank list.
Lambda function to add new bank details to list of banks.

// This is to add new bank details
final BankOperations<List<Bank>> add = (bank, banks) -> {
	banks.add(bank);
	return banks;
};

Lambda function to delete existing bank details from list of banks.

// This is to delete bank from the list
final BankOperations<List<Bank>> delete = (bank, banks) -> {
	banks.remove(bank);
	return banks;
};

3) Finally, use or call the lambda functions add and delete.

// To add new bank sbi1 to bank list banks
add.operation(sbi1, banks);
// To delete existing bank icici bank from banks list.
delete.operation(icici, banks);

Here is complete example,

UserdefinedLambdaExpExample.java

package com.devjavasource.java8.lambdaexpressions;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class UserdefinedLambdaExpExample {

	public static void main(String[] args) {
		// This is to add new bank details
		final BankOperations<List<Bank>> add = (bank, banks) -> {
			banks.add(bank);
			return banks;
		};
		// This is to delete bank from the list
		final BankOperations<List<Bank>> delete = (bank, banks) -> {
			banks.remove(bank);
			return banks;
		};

		// How to manipulate collections as parameter to lambda expression
		Bank sbi = new Bank("SBI", new Double(11));
		Bank icici = new Bank("ICICI", new Double(33));
		Bank hdfc = new Bank("HDFC", new Double(22));
		// Create a collection - List
		List<Bank> banks = new ArrayList<>();
		banks.add(sbi);
		banks.add(icici);
		banks.add(hdfc);

		final Bank sbi1 = new Bank("SBI", new Double(12));
		// Finally, use the lambda functions.
		System.out.println("BANK LIST BEFORE ADDING NEW BANK\n**********************************");
		printlBankDetails(banks.stream());
		System.out
				.println("BANK LIST AFTER ADDING NEW BANK\n***********************************");
		add.operation(sbi1, banks);
		printlBankDetails(banks.stream());
		System.out.println("==========================================================");
		// Delete some bank from the list
		System.out
				.println("BANK LIST AFTER DELETING ICICI BANK\n***********************************");
		delete.operation(icici, banks);
		printlBankDetails(banks.stream());
	}

	static interface BankOperations<T> {
		public T operation(Bank sbi1, List<Bank> banks);
	}

	private static void printlBankDetails(final Stream<Bank> inBankStream) {
		inBankStream.forEach(each -> {
			System.out.println("Bank Name : " + each.getBankName());
			System.out.println("Bank IFSI Code : " + each.getIfscCode());
		});
	}
	
	public static class Bank {
		private String bankName;
		private Double ifscCode;

		public Bank(final String inBankName, final Double inIfscCode) {
			ifscCode = inIfscCode;
			bankName = inBankName;
		}

		public Double getIfscCode() {
			return ifscCode;
		}

		public String getBankName() {
			return bankName;
		}
	}
}

Out Put:

BANK LIST BEFORE ADDING NEW BANK
**********************************
Bank Name : SBI
Bank IFSI Code : 11.0
Bank Name : ICICI
Bank IFSI Code : 33.0
Bank Name : HDFC
Bank IFSI Code : 22.0
BANK LIST AFTER ADDING NEW BANK
***********************************
Bank Name : SBI
Bank IFSI Code : 11.0
Bank Name : ICICI
Bank IFSI Code : 33.0
Bank Name : HDFC
Bank IFSI Code : 22.0
Bank Name : SBI
Bank IFSI Code : 12.0
==========================================================
BANK LIST AFTER DELETING ICICI BANK
***********************************
Bank Name : SBI
Bank IFSI Code : 11.0
Bank Name : HDFC
Bank IFSI Code : 22.0
Bank Name : SBI
Bank IFSI Code : 12.0

How to pass a lambda function as parameter value :
Another way to use the interface is to define methods that take a interface parameter and
then pass a lambda function as the parameter value.

Here are same three steps to follow,
1) Interface with one method declaration.
2) Define functions that have the interface type as their parameter.
3) Call the function, use a lambda as the parameter.

LambdaFunctionAsParameterValueExample.java

package com.venkatajavasource.java8.lambdaexpressions;

public class LambdaFunctionAsParameterValueExample {

	public static void main(String[] args) {
		testIntegerOperation((Integer n) -> n + 1);
		System.out.println();
		testCharacterOperation((Character ch) -> new Character((char)(ch.charValue() + 1)));
	}

	// Interface with one method declaration.
	static interface IncrementOperator<T> {
		T increment(T t);
	}

	// Define functions that have the interface type as their parameter
	public static void testIntegerOperation(IncrementOperator<Integer> o) {
		System.out.printf("test Integer incremant operation :%d", o.increment(110));
	}
	public static void testCharacterOperation(IncrementOperator<Character> o) {
		System.out.printf("test Character increment operation :%s", o.increment('A'));
	}
}

Select “Run As” -> “Java Application”
Out Put :

test Integer incremant operation :111
test Character increment operation :B

How Closures are differ from Lambdas?

Closures are a subset of lambda functions that close over variables not in their parameter list.
Closures can be simulated in Java using anonymous inner classes that reference variables not in the inner class scope.

Java inner classes may use variables defined in outer (enclosing) class scope, but they can’t change the values of
the outer class variable. In fact, outer class variables used in inner classes are required to be final.
Java makes a copy of the final out class variable, so while it looks like a closure, its really not.

What is a closure?
A closure is a function that uses variables not explicitly declared in the parameter list.
In fact, a closure may enclose variables that in the closure.

//Closure example
Integer A = 5;
Integer add( int x ) 
{ return x + A; } // Here free variable "A" is used add function body
//Not a closure example
Integer add( int x ) 
{ 
    Integer A = 5;
    return x + A; // Here "A" is not a free variable, it is declared inside add function body.
} 

Here is a complete example of closure and non-closure function.

ClosureExample.java

package com.devjavasource.java8.lambdaexpressions;

public class ClosureExample {

	public static void main(String[] args) {		
		System.out.println("CLOSURE FUNCTION CALL : " + closureFunction(1));
		
		System.out.println("NOT CLOSURE FUNCTION CALL : " + notClosureFunction(1));
	}
	
	static Integer a = 1;
	static Integer notClosureFunction(Integer b) {
	 return (a + b);
	}

	static Integer closureFunction(Integer c) {
	 Integer a = 2;
	 return (a + c);
	};
}

Out Put:

CLOSURE FUNCTION CALL : 3
NOT CLOSURE FUNCTION CALL : 2

In case method local variable and free variable values are same, then we can not find any difference in results.

Download complete source code Here,
JAVA8Features_LambdaExpressions

*** Venkat – Happy leaning ****