Memory utilization, own functional interface and Traditional style to Lambda


Lambdas and memory utilization

Since Java lambdas are closures, they can "capture" the values of variables in the enclosing lexical scope. While not all lambdas capture anything -- simple lambdas like s -> s.length() capture nothing and are called stateless -- capturing lambdas require a temporary object to hold the captured variables. In this code snippet, the lambda () -> j is a capturing lambda, and may cause an object to be allocated when it is evaluated:

public static void main(String[] args) throws Exception {
     for (int i = 0; i < 1000000000; i++) {
           int j = i;
           doSomethingWithLambda(() -> j);
     }
}

Although it might not be immediately obvious since the new keyword doesn't appear anywhere in the snippet, this code is liable to create 1,000,000,000 separate objects to represent the instances of the () -> j lambda expression. However, it should also be noted that future versions of Java1 may be able to optimize this so that at runtime the lambda instances were reused, or were represented in some other way.

1 - For instance, Java 9 introduces an optional "link" phase to the Java build sequence which will provide the opportunity for doing global optimizations like this.


Using lambda expression with your own functional interface

Lambdas are meant to provide inline implementation code for single method interfaces and the ability to pass them around as we have been doing with normal variables. We call them Functional Interface.

For example, writing a Runnable in anonymous class and starting a Thread looks like:

//Old way
new Thread(
	new Runnable(){
		public void run(){
			System.out.println("run logic...");
		}
	}
).start();
 
//lambdas, from Java 8
new Thread(
	()-> System.out.println("run logic...")
).start();
 
Now, in line with above, lets say you have some custom interface:
 
interface TwoArgInterface {
	int operate(int a, int b);
}

How do you use lambda to give implementation of this interface in your code? Same as Runnable example shown above. See the driver program below:

public class CustomLambda {
	public static void main(String[] args) {
		TwoArgInterface plusOperation = (a, b) -> a + b;
		TwoArgInterface divideOperation = (a,b)->{
			if (b==0) throw new IllegalArgumentException("Divisor can not be 0");
			return a/b;
		};
		System.out.println("Plus operation of 3 and 5 is: " + plusOperation.operate(3, 5));
		System.out.println("Divide operation 50 by 25 is: " + divideOperation.operate(50, 25));
	}
}

Traditional style to Lambda style

Traditional way

For example, writing a Runnable in anonymous class and starting a Thread looks like:

interface MathOperation{
	boolean unaryOperation(int num);
}
 
public class LambdaTry {
	public static void main(String[] args) {
		MathOperation isEven = new MathOperation() {
			@Override
			public boolean unaryOperation(int num) {
				return num%2 == 0;
			}
		};
 
		System.out.println(isEven.unaryOperation(25));
		System.out.println(isEven.unaryOperation(20));
	}
}

Lambda style

1. Remove class name and functional interface body.
 
	public class LambdaTry {
		public static void main(String[] args) {
			MathOperation isEven = (int num) -> {
				return num%2 == 0;
			};
 
			System.out.println(isEven.unaryOperation(25));
			System.out.println(isEven.unaryOperation(20));
		}
	}
 
2. Optional type declaration
 
	MathOperation isEven = (num) -> {
		return num%2 == 0;
	};
 
3. Optional parenthesis around parameter, if it is single parameter
 
	MathOperation isEven = num -> {
		return num%2 == 0;
	};
 
4. Optional curly braces, if there is only one line in function body
5. Optional return keyword, if there is only one line in function body
 
	MathOperation isEven = num -> num%2 == 0;

Basic Programs