Fundamentals 13 min read

Introduction to Java Lambda Expressions and Common Usage Examples

This article introduces Java Lambda expressions, explains the functional interface requirements, demonstrates basic and simplified syntax, and provides numerous practical examples such as method references, constructor references, thread creation, collection iteration, element removal, sorting, and closure behavior.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Introduction to Java Lambda Expressions and Common Usage Examples

Lambda Introduction

Lambda expressions are a new feature in JDK 8 that can replace most anonymous inner classes, allowing more elegant Java code, especially for collection traversal and other operations, greatly improving code structure.

JDK also provides many built‑in functional interfaces, making the use of Lambdas convenient and efficient.

Requirements for Interfaces

Although Lambdas can provide simple implementations for some interfaces, not all interfaces are suitable; a Lambda can only be used when the interface has exactly one abstract method to implement.

In JDK 8, the default keyword allows methods to have a default implementation, which does not affect Lambda usage.

@FunctionalInterface

The @FunctionalInterface annotation marks a functional interface, requiring that it contain only one abstract method; it is often used together with Lambda expressions.

Basic Lambda Syntax

Six functional interfaces are defined below and will be used throughout the examples.

/** Multi‑parameter, no return */
@FunctionalInterface
public interface NoReturnMultiParam {
    void method(int a, int b);
}

/** No‑parameter, no return */
@FunctionalInterface
public interface NoReturnNoParam {
    void method();
}

/** Single‑parameter, no return */
@FunctionalInterface
public interface NoReturnOneParam {
    void method(int a);
}

/** Multi‑parameter, returns int */
@FunctionalInterface
public interface ReturnMultiParam {
    int method(int a, int b);
}

/** No‑parameter, returns int */
@FunctionalInterface
public interface ReturnNoParam {
    int method();
}

/** Single‑parameter, returns int */
@FunctionalInterface
public interface ReturnOneParam {
    int method(int a);
}

The syntax is () -> {} , where () describes the parameter list, {} the method body, and -> is the lambda operator.

import lambda.interfaces.*;

public class Test1 {
    public static void main(String[] args) {
        // No‑parameter, no return
        NoReturnNoParam noReturnNoParam = () -> {
            System.out.println("NoReturnNoParam");
        };
        noReturnNoParam.method();

        // Single‑parameter, no return
        NoReturnOneParam noReturnOneParam = (int a) -> {
            System.out.println("NoReturnOneParam param:" + a);
        };
        noReturnOneParam.method(6);

        // Multi‑parameter, no return
        NoReturnMultiParam noReturnMultiParam = (int a, int b) -> {
            System.out.println("NoReturnMultiParam param:" + "{" + a + "," + b + "}");
        };
        noReturnMultiParam.method(6, 8);

        // No‑parameter, returns int
        ReturnNoParam returnNoParam = () -> {
            System.out.print("ReturnNoParam");
            return 1;
        };
        int res = returnNoParam.method();
        System.out.println("return:" + res);

        // Single‑parameter, returns int
        ReturnOneParam returnOneParam = (int a) -> {
            System.out.println("ReturnOneParam param:" + a);
            return 1;
        };
        int res2 = returnOneParam.method(6);
        System.out.println("return:" + res2);

        // Multi‑parameter, returns int
        ReturnMultiParam returnMultiParam = (int a, int b) -> {
            System.out.println("ReturnMultiParam param:" + "{" + a + "," + b + "}");
            return 1;
        };
        int res3 = returnMultiParam.method(6, 8);
        System.out.println("return:" + res3);
    }
}

Simplified Lambda Syntax

Further simplifications can be made by observing the following code.

import lambda.interfaces.*;

public class Test2 {
    public static void main(String[] args) {
        // 1. Omit parameter types (all parameters must be omitted)
        NoReturnMultiParam lambda1 = (a, b) -> {
            System.out.println("Simplify parameter types");
        };
        lambda1.method(1, 2);

        // 2. Omit parentheses for a single parameter
        NoReturnOneParam lambda2 = a -> {
            System.out.println("Simplify parentheses");
        };
        lambda2.method(1);

        // 3. Omit braces when the body has a single statement
        NoReturnNoParam lambda3 = () -> System.out.println("Simplify braces");
        lambda3.method();

        // 4. Omit braces for a single return statement
        ReturnOneParam lambda4 = a -> a + 3;
        System.out.println(lambda4.method(5));

        // 5. Concise multi‑parameter return
        ReturnMultiParam lambda5 = (a, b) -> a + b;
        System.out.println(lambda5.method(1, 1));
    }
}

Common Lambda Expression Examples

Method Reference in Lambda

Sometimes we can refer directly to an already implemented method instead of writing a new anonymous class.

Syntax

ClassName::methodName for static methods, or instance::methodName for instance methods.

public class Exe1 {
    public static void main(String[] args) {
        ReturnOneParam lambda1 = a -> doubleNum(a);
        System.out.println(lambda1.method(3));

        // Method reference to static method
        ReturnOneParam lambda2 = Exe1::doubleNum;
        System.out.println(lambda2.method(3));

        Exe1 exe = new Exe1();
        // Method reference to instance method
        ReturnOneParam lambda4 = exe::addTwo;
        System.out.println(lambda4.method(2));
    }

    public static int doubleNum(int a) {
        return a * 2;
    }

    public int addTwo(int a) {
        return a + 2;
    }
}

Constructor Reference

Interfaces can act as object factories; using ClassName::new creates instances.

interface ItemCreatorBlankConstruct {
    Item getItem();
}

interface ItemCreatorParamContruct {
    Item getItem(int id, String name, double price);
}

public class Exe2 {
    public static void main(String[] args) {
        ItemCreatorBlankConstruct creator = () -> new Item();
        Item item = creator.getItem();

        ItemCreatorBlankConstruct creator2 = Item::new;
        Item item2 = creator2.getItem();

        ItemCreatorParamContruct creator3 = Item::new;
        Item item3 = creator3.getItem(112, "Mouse", 135.99);
    }
}

Creating Threads with Lambda

Instead of an anonymous inner class overriding run() , a Lambda can be used.

Thread t = new Thread(() -> {
    for (int i = 0; i < 10; i++) {
        System.out.println(2 + ":" + i);
    }
});
 t.start();

Iterating Collections

The forEach(Consumer action) method can be used with Lambdas to traverse elements.

@FunctionalInterface
public interface Consumer
{
    void accept(T t);
    // ...
}
ArrayList
list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5);
list.forEach(System.out::println);
list.forEach(element -> {
    if (element % 2 == 0) {
        System.out.println(element);
    }
});

Removing Elements from a Collection

The removeIf(Predicate filter) method removes elements that match a condition.

ArrayList
items = new ArrayList<>();
items.add(new Item(11, "Toothbrush", 12.05));
items.add(new Item(5, "Japanese toilet seat", 999.05));
items.add(new Item(7, "Gree air conditioner", 888.88));
items.add(new Item(17, "Soap", 2.00));
items.add(new Item(9, "Refrigerator", 4200.00));

items.removeIf(ele -> ele.getId() == 7);
items.forEach(System.out::println);

Sorting Elements in a Collection

Lambda expressions simplify sorting with a comparator.

ArrayList
list = new ArrayList<>();
list.add(new Item(13, "Vest", 7.80));
list.add(new Item(11, "Half‑sleeve", 37.80));
list.add(new Item(14, "Windbreaker", 139.80));
list.add(new Item(12, "Thermal pants", 55.33));

list.sort((o1, o2) -> o1.getId() - o2.getId());
System.out.println(list);

Closure Issue in Lambda Expressions

Like anonymous inner classes, Lambdas capture variables; the captured variable is effectively final and cannot be modified after capture.

import java.util.function.Consumer;
public class Main {
    public static void main(String[] args) {
        int num = 10;
        Consumer
consumer = ele -> {
            System.out.println(num);
        };
        // num = num + 2; // illegal – would cause a compile‑time error
        consumer.accept("hello");
    }
}
JavalambdaThreadCollectionsFunctionalInterfaceMethodReference
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.