Dr. Vatsal Shah
Subject Material

Java · Collections · Topic 9

Lambda Expressions

Write concise behavior with lambdas, functional interfaces, built-in functions, method references, and safe variable capture.

Topic progress · 1 of 19 sections

Step 1 of 19

9.1 Introduction

Learning objective

Define lambda expressions and recognize their principal Java uses.

A lambda expression is a short way to represent a block of code that can be passed to a method. It has no method name, may accept parameters, and may return a value.

Common uses

  • Functional interfaces
  • Collections
  • Streams API
  • Event handling
  • Multithreading
Check your understanding: In which Java version were lambda expressions introduced?

Java 8.

Step 2 of 19

9.2 Basic Syntax

Learning objective

Read the parameter list, arrow, and body of a lambda.

Expression and block forms
(parameters) -> expression
(parameters) -> {
    statements;
}

(a, b) -> a + b
Check your understanding: What does (a,b) -> a+b return?

The sum of a and b.

Step 3 of 19

9.3 Lambda Expression Forms

Learning objective

Write lambdas with zero, one, or multiple parameters and expression or block bodies.

Lambda forms
FormExample
No parameter() -> System.out.println("Hello Java")
One parametername -> System.out.println(name)
Multiple parameters(a, b) -> a + b
Explicit types(int a, int b) -> a + b
Statement block(a, b) -> { int result=a+b; return result; }
Check your understanding: When braces surround multiple value-returning statements, what keyword is required?

return.

Step 4 of 19

9.4 Functional Interface

Learning objective

Connect a lambda to an interface containing one abstract method.

FunctionalInterfaceDemo.java
@FunctionalInterface
interface Greeting {
    void sayHello();
}
public class FunctionalInterfaceDemo {
    public static void main(String[] args) {
        Greeting greeting = () -> System.out.println("Hello Java");
        greeting.sayHello();
    }
}
Output
Hello Java
Check your understanding: How many abstract methods does a functional interface contain?

Exactly one.

Step 5 of 19

9.5 @FunctionalInterface Annotation

Learning objective

Use the annotation to make functional-interface intent compiler-checked.

Annotated interface
@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);
    default void describe() { System.out.println("Calculator"); }
}

Allowed members

  • One abstract method
  • Any number of default methods
  • Any number of static methods
  • Methods inherited from Object
Check your understanding: May a functional interface contain default and static methods?

Yes, in any number.

Step 6 of 19

9.6 Lambda with Parameters and Return Value

Learning objective

Implement multiple calculations through one functional interface.

LambdaDemo.java
@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);
}
public class LambdaDemo {
    public static void main(String[] args) {
        Calculator addition = (a, b) -> a + b;
        Calculator subtraction = (a, b) -> a - b;
        Calculator multiplication = (a, b) -> a * b;
        System.out.println("Result: " + addition.calculate(10, 20));
        System.out.println("Subtract: " + subtraction.calculate(10, 5));
        System.out.println("Multiply: " + multiplication.calculate(10, 5));
    }
}
Output
Result: 30
Subtract: 5
Multiply: 50
Check your understanding: What result does addition.calculate(10,20) produce?

30.

Step 7 of 19

9.7 Lambda versus Anonymous Class

Learning objective

Replace a single-method anonymous implementation with a lambda.

Anonymous class and lambda
Runnable verbose = new Runnable() {
    public void run() { System.out.println("Task is running"); }
};

Runnable concise = () -> System.out.println("Task is running");
Check your understanding: Which version is normally shorter for Runnable?

The lambda version.

Step 8 of 19

9.8 Lambda with Collections

Learning objective

Process each collection element with forEach().

LambdaCollectionDemo.java
import java.util.Arrays;
import java.util.List;
public class LambdaCollectionDemo {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Amit", "Neha", "Raj");
        names.forEach(name -> System.out.println(name));
    }
}
Output
Amit
Neha
Raj
Check your understanding: Which method reference is equivalent to name -> System.out.println(name)?

System.out::println.

Step 9 of 19

9.9 Sorting Using Lambda

Learning objective

Supply ascending, descending, and length comparators as lambdas.

LambdaSortDemo.java
import java.util.*;
public class LambdaSortDemo {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>(Arrays.asList("Raj", "Amit", "Neha"));
        names.sort((first, second) -> first.compareTo(second));
        System.out.println(names);
        names.sort((first, second) -> second.compareTo(first));
        System.out.println(names);
        names.sort((first, second) -> Integer.compare(first.length(), second.length()));
        System.out.println(names);
    }
}
Output
[Amit, Neha, Raj]
[Raj, Neha, Amit]
[Raj, Neha, Amit]
Check your understanding: How can strings be sorted by length?

Compare first.length() and second.length(), preferably with Integer.compare.

Step 10 of 19

9.10 Built-in Functional Interfaces

Learning objective

Identify Java’s core java.util.function interfaces.

Core functional interfaces
InterfaceRole
Predicate<T>Tests a value
Function<T,R>Transforms a value
Consumer<T>Performs an action
Supplier<T>Provides a value
Check your understanding: Which package contains these interfaces?

java.util.function.

Step 11 of 19

9.11 Predicate<T>

Learning objective

Test a value and obtain a boolean result.

PredicateDemo.java
import java.util.function.Predicate;
public class PredicateDemo {
    public static void main(String[] args) {
        Predicate<Integer> isEven = number -> number % 2 == 0;
        System.out.println(isEven.test(10));
        System.out.println(isEven.test(15));
    }
}
Output
true
false

Common uses

  • Filtering
  • Testing conditions
  • Validation
Check your understanding: What does isEven.test(15) return?

false.

Step 12 of 19

9.12 Combining Predicates

Learning objective

Compose conditions with and(), or(), and negate().

PredicateCombinationDemo.java
import java.util.function.Predicate;
public class PredicateCombinationDemo {
    public static void main(String[] args) {
        Predicate<Integer> greaterThan10 = number -> number > 10;
        Predicate<Integer> lessThan50 = number -> number < 50;
        Predicate<Integer> condition = greaterThan10.and(lessThan50);
        System.out.println(condition.test(25));
        System.out.println(condition.negate().test(25));
    }
}
Output
true
false
Check your understanding: Does greaterThan10.and(lessThan50).test(25) return true?

Yes.

Step 13 of 19

9.13 Function<T, R>

Learning objective

Transform an input of type T into a result of type R.

FunctionDemo.java
import java.util.function.Function;
public class FunctionDemo {
    public static void main(String[] args) {
        Function<String, Integer> length = text -> text.length();
        Function<Integer, Integer> square = number -> number * number;
        System.out.println(length.apply("Java"));
        System.out.println(square.apply(6));
    }
}
Output
4
36
Check your understanding: What are T and R in Function<String,Integer>?

String is the input type; Integer is the result type.

Step 14 of 19

9.14 Consumer<T>

Learning objective

Perform an action with one input and no returned result.

ConsumerDemo.java
import java.util.function.Consumer;
public class ConsumerDemo {
    public static void main(String[] args) {
        Consumer<String> display = name -> System.out.println(name);
        display.accept("Amit");
    }
}
Output
Amit
Check your understanding: What is Consumer’s main method?

accept(T value).

Step 15 of 19

9.15 Supplier<T>

Learning objective

Provide a value without receiving an argument.

SupplierDemo.java
import java.util.function.Supplier;
public class SupplierDemo {
    public static void main(String[] args) {
        Supplier<String> defaultValue = () -> "Java";
        System.out.println(defaultValue.get());
    }
}
Output
Java

Common uses

  • Generating values
  • Creating objects
  • Providing defaults
Check your understanding: Does Supplier accept an input parameter?

No.

Step 16 of 19

9.16 Comparison of Functional Interfaces

Learning objective

Compare input, output, and method contracts.

Functional-interface comparison
InterfaceInputOutputMain method
Predicate<T>One valuebooleantest()
Function<T,R>One valueAnother valueapply()
Consumer<T>One valueNo resultaccept()
Supplier<T>No inputOne valueget()
Check your understanding: Which interface has no input but produces a value?

Supplier<T>.

Step 17 of 19

9.17 Method References

Learning objective

Replace a lambda that only calls an existing method with :: syntax.

MethodReferenceDemo.java
import java.util.Arrays;
import java.util.List;
public class MethodReferenceDemo {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Amit", "Neha", "Raj");
        names.forEach(System.out::println);
    }
}
Output
Amit
Neha
Raj
Equivalent forms
name -> System.out.println(name)
System.out::println
Check your understanding: What operator introduces a method reference?

The double colon (::).

Step 18 of 19

9.18 Types of Method References

Learning objective

Recognize static, bound instance, unbound instance, and constructor references.

Method-reference types
TypeFormExample
Static methodClassName::staticMethodInteger::parseInt
Particular objectobject::instanceMethodSystem.out::println
Arbitrary objectClassName::instanceMethodString::compareToIgnoreCase
ConstructorClassName::newArrayList::new
Check your understanding: Which form creates objects?

ClassName::new.

Step 19 of 19

9.19 Local Variables in Lambda Expressions

Learning objective

Apply the final-or-effectively-final capture rule.

LambdaCaptureDemo.java
import java.util.function.Function;
public class LambdaCaptureDemo {
    public static void main(String[] args) {
        int multiplier = 5; // effectively final
        Function<Integer, Integer> multiply = number -> number * multiplier;
        System.out.println(multiply.apply(4));
    }
}
Output
20
Check your understanding: Can a lambda capture multiplier after multiplier is reassigned?

No.