Java 8 – Anonymous Inner class v/s Lambda Expression

In this article, we will discuss difference between Anonymous Inner class and Lambda expression

First, we will look at what is anonymous inner classes in Java

1. Anonymous Inner class

  • It is very simple to understand, a class which has no name at all
  • In Java, every class has name which can be used to inherit further and can be used to create objects & invoke its method/behaviors using instantiated objects
  • But in anonymous inner class, it is defined without name and used where it is defined i.e.; it scope limits to where is defined
  • So further usage like inheriting and creating objects isn’t possible
  • Note: Although it looks like similar to Lambda expression but their comparison is incomparable, we will look these points at the very end of this topic
  • We will look at few examples of Anonymous inner class before comparing them with Lambda Expression (code-wise)

Example 1.A: Defining custom sorting logic using Comparator interface

  • Below example shows that Comparator interface is instantiated to provide custom logic to sort list of String values
  • It is used where it is defined i.e.; inside method itself
  • Its further usage is not allowed, as it will act as local variable inside method it is defined
package net.bench.resources.custom.sorting.logic;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class MyCustomComparator {

	public static void main(String[] args) {

		// Step 1: define anonymous inner class for Comparator<String>
		Comparator<String> cmp = new Comparator<String>() {

			@Override
			public int compare(String str1, String str2) {
				return str1.compareTo(str2);
			}
		};

		// Step 2: define ArrayList and add String values
		ArrayList<String> al = new ArrayList<String>();
		al.add("Poland");
		al.add("Finland");
		al.add("Denmark");
		al.add("Sweden");
		al.add("Norway");
		System.out.println("Before Sorting - " + al);

		// Step 3: sort ArrayList using above anonymous inner class Comparator
		Collections.sort(al, cmp);
		System.out.println("After Sorting - " + al);
	}
}

Output:

Before Sorting - [Poland, Finland, Denmark, Sweden, Norway]
After Sorting - [Denmark, Finland, Norway, Poland, Sweden]

Example 1.B: Creating Thread using using Runnable interface

  • Below example shows that Runnable interface is instantiated to provide logic for new thread inside run() method
package net.bench.resources.threads;

public class MyRunnable {

	public static void main(String[] args) {

		// Step 1: define anonymous inner class for Runnable
		Runnable r = new Runnable() {

			@Override
			public void run() {
				System.out.println("Hello World in Child Thread");
			}
		};

		// Step 2: define Thread passing above Runnable instance
		Thread t = new Thread(r);

		// Step 2.A start runnable thread
		t.start();

		// main thread
		System.out.println("Hello World in main Thread");
	}
}

Output:

Hello World in main Thread
Hello World in Child Thread

2. Lambda Expression

  • It is a new feature introduced in Java 1.8 version
  • Which has special syntax like ( argument_list ) -> { function_body };
  • Using Lambda Expression, code looks more concise which means less number of lines of code comparing with Anonymous Inner class
  • Let us look at the same example discussed above using lambda expression

Example 2.A: Defining custom sorting logic using Comparator interface

  • Above 1.A anonymous inner class example requires 5-6 lines of custom logic using Comparator interface for sorting
  • The same example is reduced to single line using lambda expression
package net.bench.resources.custom.sorting.logic;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class MyComparator {

	public static void main(String[] args) {

		// Step 1: define Lambda Expression for Comparator<String>
		Comparator<String> cmp = (str1, str2) -> str1.compareTo(str2);

		// Step 2: define ArrayList and add String values
		ArrayList<String> al = new ArrayList<String>();
		al.add("Poland");
		al.add("Finland");
		al.add("Denmark");
		al.add("Sweden");
		al.add("Norway");
		System.out.println("Before Sorting - " + al);

		// Step 3: sort ArrayList using above anonymous inner class Comparator
		Collections.sort(al, cmp);
		System.out.println("After Sorting - " + al);
	}
}

Output:

Before Sorting - [Poland, Finland, Denmark, Sweden, Norway]
After Sorting - [Denmark, Finland, Norway, Poland, Sweden]

Example 2.B: Creating Thread using using Runnable interface

  • Above 2.A anonymous inner class example requires 5-6 lines of code for creating/spawning new thread from main thead
  • Whereas same example is reduced to single line using lambda expression
package net.bench.resources.threads;

public class MyRunnableUsingLambda {

	public static void main(String[] args) {

		// Step 1: define Lambda Expression for Runnable
		Runnable r = () -> System.out.println("Hello World in Child Thread");

		// Step 2: define Thread passing above Runnable instance
		Thread t = new Thread(r);

		// Step 2.A start runnable thread
		t.start();

		// main thread
		System.out.println("Hello World in main Thread");
	}
}

Output:

Hello World in main Thread
Hello World in Child Thread

3. Anonymous Inner class v/s Lambda Expression

3.1 Anonymous Inner class :

  • It can extend either concrete class or abstract class
  • It can implement interface also
  • An interface that anonymous inner class implements can contain any number of abstract methods

3.2 Lambda Expression :

  • Lambda Expression can implement or provide implementation for Functional Interface only
  • Functional Interface contains exactly one abstract method
  • In addition to this, it can contains any number of default or static methods, which is another new feature introduced in Java 1.8 version

References:


Happy Coding !!
Happy Learning !!

Java 8 - default and static methods
Java 8 - Functional Interface with examples