Java8 Lambdas

Lambdas enable functional programming in Java. Concept of Lambda is available in many languages but the beauty of it in Java is its BACKWARD COMPATIBILITY. In this post we will discuss below areas

  • Concept
  • Syntax
  • Functional Interfaces
  • Variable Capture
  • Method References
  • Default Methods


Lambda can be defined as

  • a way of defining anonymous functions
  • It can be passed to variables
  • It can be passed to functions
  • Can be returned from functions

What are lambda good for?

  • These are the base for functional programming model
  • Makes parallel programming easier: If we want to make 100s of cores busy then its easier to do with functional programming than that of the object oriented programming
  • Write compact code (Hadoop1 in Java: 200k lines of code VS Spark1 in Scala: 25k Lines of Code)
  • Richer Data Structure Collections
  • Develop Cleaner APIs


List<Integer> integers = Arrays.asList(1,2,3);
integers.forEach(x -> System.out.println(x));
integers.forEach((x) -> {
    x = x+10;
integers.forEach((Integer x) -> {
    x = x+10;

We can explicitly mention types, but Java8 compiler is able to do Type Inference

Lambda Expression in Java (from video: A Peek Under the Hood by Brian) is converted into a Function and then we call the generated function

Functional Interfaces (FI)

An interface with just one method (one NON-DEFAULT Method) is called a Functional Interface.

Prior to Java8 we use to write the function with signature, open a curly brace and then write body of the function and close it but In Java8:

// define FI
    // enforces that the interface is FI (it fails compilation if below interface has more than one method)
    // Its optional and can be applied only to interfaces
public interface Consumer<T> {
    void accept(T t);

// give the definition
Consumer<Integer> consumer = x -> System.out.println(x);

// use it
List<Integer> integers = Arrays.asList(1,2,3);

Few things to notice here:

  • Here we are separating the body of the function (Line #10) from its signature(Line #6).
  • The method generated from lambda expression must have same signature as that of the FI(see Line#67: lambda takes one arg ‘x’, throws no Exception and returns nothing)
  • In Java8, the type of the lambda expression is same as that of the FI that lambda is assigned to. (see Line#67)

Variable Capture (VC)

Lambdas can interact with variables (local, instance and static) defined outside the body of lambda (aka VC).

List<Integer> integers = Arrays.asList(1,2,3);
int vc=10;
integers.forEach(x -> System.out.println(x+vc));

Note: Local variables accessed and used inside the Lambda are final and cannot be modified.

Lambda vs Anonymous Inner Classes

  • Inner classes can have state in the form of class level instance variables whereas lambdas cannot.
  • Inner Classes can have multiple methods whereas Lambda’s cannot
  • ‘this’ points to the object instance of anonymous inner class whereas it points to the enclosing object for lambda

java.util.function.* contains 43 most commonly used functional interfaces

  • Consumer: functions which takes argument of type T and returns void
  • Supplier: functions that takes no argument and returns a result of type T
  • Predicate: functions which takes argument of type T and returns boolean
  • Function<T, R>: function that takes an argument of type T and returns a result of type R

Method References (MRs)

As lambda being a way to define anonymous function, there is a good chance that the function we want to use exists already. In these cases, MRs can be used to pass an existing function in place where lambda is expected

public interface Consumer<T> {
    void accept(T t);

public void doSomething(Integer x) {

Consumer<Integer> cons1 = x -> doSomething(x);
// Reuse with MR
Consumer<Integer> cons2 = Example::doSomething;

Note: The signature of the referenced method must match the signature of FI method.

By looking at above definition it is obvious that MR works on method with only one argument and no return type

Referencing a Constructor: Constructor method references are quite handy while working with Streams

// Create a new function which has a method that takes 'String' as parameter (LHS to arrow), returns 'Integer' (RHS to arrow as body of method)
Function<String, Integer> mapper1 = x -> new Integer(x);

// Refer a Cons
Function<String, Integer> mapper2 = x -> Integer::new;

References to a specific object instance method:

Consumer<Integer> cons1 = x -> doSomething(x);
// can also be written as: this invokes the println() method on System.out object by passing param '2'
Consumer<Integer> cons2 = System.out::println;

Default Methods ***

This is very important feature because it addresses Interface Evolution Problem: How a published interface (like List, Iterable, etc) can be evolved without breaking existing implementations (backward compatible)

Default Method: A default method on a java interface has an implementation provided in the interface and is inherited by the classes that implements it.

public Iterable<T> { 
    Iterator<T> iterator;
    default void forEach(Consumer<? super T> action) {
        for(T t: this) {


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s


Mostly technology with occasional sprinkling of other random thoughts


Amir Amintabar's personal page

101 Books

Reading my way through Time Magazine's 100 Greatest Novels since 1923 (plus Ulysses)

Seek, Plunnge and more...

My words, my world...

ARRM Foundation

Do not wait for leaders; do it alone, person to person - Mother Teresa

Executive Management

An unexamined life is not worth living – Socrates


A topnotch site


Just another site

coding algorithms

"An approximate answer to the right problem is worth a good deal more than an exact answer to an approximate problem." -- John Tukey

%d bloggers like this: