JAVA • JAVA-SPECIFIC TOPICS

Lambda Expressions — Write basic lambda expressions

Learn how to write concise, inline functions that make your Java code shorter and more expressive.

Historical Context & Motivation

For nearly two decades, Java was one of the most popular programming languages in the world — but it had a reputation for being verbose. Simple tasks like sorting a list or responding to a button click required writing entire classes just to define a tiny piece of behavior. Developers often joked that Java made you write ten lines of code to do what other languages accomplished in one. The introduction of lambda expressions in Java 8 changed all of that, bringing a powerful feature from the world of functional programming into the Java ecosystem.

The idea behind lambda expressions is not new. The concept traces its roots all the way back to the 1930s and a branch of mathematics called lambda calculus, developed by mathematician Alonzo Church. Over the decades, many programming languages adopted this concept — Lisp in the 1950s, Python in the 1990s, and JavaScript shortly after. Java developers had been requesting this feature for years before it finally arrived.

1936
Lambda Calculus Invented
Alonzo Church introduces lambda calculus, a formal system for expressing computation using anonymous functions. This mathematical framework laid the theoretical groundwork for functional programming.
1958
Lisp Adopts Lambdas
Lisp, one of the earliest programming languages, includes lambda expressions as a core feature, allowing programmers to pass functions as data.
1995
Java Released Without Lambdas
Java 1.0 is released by Sun Microsystems. It uses anonymous inner classes for inline behavior, which are functional but notoriously verbose.
2014
Java 8 Introduces Lambdas
After years of community demand, Java 8 officially adds lambda expressions, along with the Stream API and functional interfaces, modernizing the language significantly.

So what problem do lambdas solve? Before Java 8, if you wanted to pass a small piece of behavior — like a custom comparator for sorting — you had to create an entire anonymous inner class with boilerplate code. Lambda expressions let you express that same behavior in a single, readable line. The central question this lesson addresses is: How do you write a lambda expression in Java, and when should you use one?

Core Principles & Definitions

Before diving into syntax, you need to understand a few foundational ideas. A lambda expression is essentially a short block of code that takes in parameters, does something, and optionally returns a value — without needing a name. Think of it as a compact, anonymous method that you can write right where you need it.

1

Anonymous Function

A lambda is a function without a name. Unlike a regular method that belongs to a class, a lambda is defined inline and used immediately or passed around as a value.
2

Functional Interface

A lambda can only be used where Java expects a functional interface — an interface with exactly one abstract method. Examples include Runnable, Comparator, and Predicate.
3

The Arrow Operator

Every lambda uses the -> (arrow) operator. The left side lists parameters, and the right side contains the body — the code that executes.
4

Type Inference

Java can often figure out the parameter types automatically from context, so you don't have to write them explicitly. This keeps lambda expressions short and clean.
5

Replaces Anonymous Classes

Lambdas replace verbose anonymous inner classes in most situations. They achieve the same result with far less code, improving readability and reducing errors.
✦ KEY TAKEAWAY
Think of a lambda expression like a sticky note with instructions. Instead of writing a full letter (an entire class) to tell someone "sort these names alphabetically," you jot a quick note and hand it over. The note has no name, no envelope — it's just the instructions themselves. That's what a lambda is: a quick, unnamed set of instructions you pass directly to the code that needs them.

Anatomy of a Lambda Expression

The best way to understand lambda syntax is to see it broken apart visually. The diagram below shows the three essential components of a lambda expression and how they map to a traditional method.

The diagram shows how a lambda expression consists of three parts: the parameter list in parentheses, the arrow operator (->), and the body. Notice how the full five-line method compresses into a single line.

As you can see, a lambda expression strips away all the ceremony of a traditional method. There's no access modifier like public, no return type declaration, and no method name. Java infers the return type from the body. When the body is a single expression, the result is automatically returned — you don't even need the return keyword.

How Lambda Syntax Works

Lambda expressions in Java follow a specific set of syntax rules. Understanding these rules will help you write lambdas confidently in different situations. Let's look at the key syntax patterns.

Syntax Pattern 1: Single Parameter, Single Expression

SINGLE PARAMETER FORM
x -> x * x
When there is exactly one parameter, parentheses are optional. The body is a single expression whose result is automatically returned.

Syntax Pattern 2: Multiple Parameters

MULTIPLE PARAMETER FORM
(a, b) -> a + b
When there are two or more parameters, parentheses are required. Types can be included — (int a, int b) -> a + b — but Java usually infers them.

Syntax Pattern 3: No Parameters

NO PARAMETER FORM
() -> System.out.println("Hello!")
When there are no parameters, you must write empty parentheses. This is commonly used with Runnable, which takes no arguments.

Syntax Pattern 4: Multi-Line Body

BLOCK BODY FORM
(x, y) -> { int sum = x + y; return sum; }
When the body has more than one statement, you must wrap it in curly braces and use an explicit return statement if the lambda needs to produce a value.
⚠️ Common Mistake
If you use curly braces for the body, you must include a return statement for any lambda that produces a value. Writing (x) -> { x * 2; } without return will cause a compilation error. Either drop the braces or add return x * 2;.

Common Functional Interfaces

A lambda expression can only appear in a context where Java expects a functional interface — an interface with exactly one abstract method. Java provides many built-in functional interfaces in the java.util.function package. The table below summarizes the most common ones you'll encounter.

Common functional interfaces used with lambda expressions
InterfaceAbstract MethodPurposeLambda Example
Predicate<T>boolean test(T t)Tests a condition and returns true/falses -> s.length() > 5
Function<T,R>R apply(T t)Transforms input of type T to output of type Rn -> n * 2
Consumer<T>void accept(T t)Performs an action with the input, returns nothings -> System.out.println(s)
Supplier<T>T get()Takes no input, produces a value() -> Math.random()
Comparator<T>int compare(T a, T b)Compares two objects for ordering(a, b) -> a.length() - b.length()
The top row shows how your lambda code flows through a functional interface to produce a result. Below, compare the 7-line anonymous inner class with the 1-line lambda equivalent.

The key insight here is that the lambda and the anonymous inner class do exactly the same thing. The lambda is simply a more concise way to implement the single abstract method defined by the functional interface. When you write s -> s.length() > 5, Java knows from the Predicate<String> context that s must be a String and that the body must return a boolean.

Worked Example: Sorting a List with a Lambda

Let's walk through a realistic example. Suppose you have a list of student names and you want to sort them by length (shortest name first). We'll write this using a lambda expression with Collections.sort().

Sorting Strings by Length Using a Lambda
1
Step 1 — Create the ListWe start by creating a list of names using Arrays.asList(): List<String> names = Arrays.asList("Alice", "Bo", "Christina", "Dan");
List contains: [Alice, Bo, Christina, Dan]
2
Step 2 — Identify the Functional InterfaceThe method Collections.sort(List<T>, Comparator<T>) expects a Comparator<String> as its second argument. Comparator is a functional interface with the abstract method int compare(String a, String b). Our lambda must take two Strings and return an int.
3
Step 3 — Write the LambdaWe need to compare two strings by their length. Subtracting one length from another gives us the correct ordering value. The lambda expression is: (a, b) -> a.length() - b.length() If a is shorter, the result is negative (a comes first). If b is shorter, the result is positive (b comes first).
4
Step 4 — Put It All TogetherThe complete sort call looks like this: Collections.sort(names, (a, b) -> a.length() - b.length()); The lambda is passed directly as the second argument — no need to create a separate class or variable.
5
Step 5 — Verify the ResultAfter calling sort, we print the list: System.out.println(names);
Output: [Bo, Dan, Alice, Christina] — sorted from shortest to longest name
💡 Pro Tip
In a single-expression lambda like (a, b) -> a.length() - b.length(), the result of the expression is automatically returned. You don't need to write return. This is one of the biggest readability advantages of lambdas.

Lambdas vs. Anonymous Classes vs. Named Methods

Lambda expressions aren't the only way to pass behavior in Java. You could also use anonymous inner classes or define a named method. Each approach has strengths and weaknesses. The table below compares them across several important dimensions.

Comparison of three approaches for passing behavior in Java
FeatureLambda ExpressionAnonymous Inner ClassNamed Method
VerbosityVery concise — often one lineVerbose — 5+ lines minimumModerate — needs method + class
ReadabilityExcellent for short logicCluttered with boilerplateBest for complex or reused logic
Can access 'this'Refers to enclosing classRefers to the anonymous class itselfRefers to the containing class
ReusabilityLow — typically used once inlineLow — single useHigh — can be called from anywhere
Interface required?Must be a functional interface (1 method)Can implement any interfaceNo interface needed
✦ WHEN TO USE LAMBDAS
Use a lambda when you need a short, one-time piece of logic — like filtering, sorting, or handling an event. If the logic is complex (more than 3–4 lines) or needs to be reused in multiple places, consider a named method instead. Think of lambdas like text messages — great for quick communication, but for something important and reusable, you'd write a proper email (a named method).

Connection to Advanced Concepts

Once you're comfortable writing basic lambdas, you'll encounter more advanced features that build on the same foundation. Two major topics await you: method references and the Stream API. Both rely heavily on lambdas and functional interfaces.

How basic lambdas connect to advanced Java features
ConceptWhat You Know Now (Lambdas)What Comes Next
Syntaxs -> s.toUpperCase()Method reference: String::toUpperCase
Usage contextSingle operations like sort or filterChained operations using Streams: filter → map → collect
Data processingProcess one element at a timeProcess entire collections with parallel pipelines
CompositionStandalone lambda for one taskCombine lambdas: predicate1.and(predicate2)

The Stream API is where lambdas truly shine. Imagine processing a list of student grades: you could filter for passing scores, convert them to letter grades, and collect the results — all in a single chain of readable method calls, each powered by a lambda. Mastering basic lambda syntax now gives you the foundation to use these powerful tools later.

🔭 Looking Ahead
A method reference like String::toUpperCase is just a shorthand for s -> s.toUpperCase(). When your lambda simply calls an existing method, the method reference form is cleaner. You'll learn more about these in a future lesson.

Practice Problems

PROBLEM 1 — CONCEPTUAL
What is a functional interface, and why is it necessary for lambda expressions in Java? Give one example of a built-in functional interface.
PROBLEM 2 — BASIC CALCULATION
Write a lambda expression that takes an integer and returns its square. Assign it to a Function<Integer, Integer> variable called square. Then show how you would call it with the value 7.
PROBLEM 3 — INTERMEDIATE
Given a List<String> words = Arrays.asList("cat", "elephant", "dog", "butterfly", "ant");, write code using Collections.sort() and a lambda expression to sort the list alphabetically in reverse order (Z to A). What will the resulting list look like?
PROBLEM 4 — APPLIED
You are building a grade calculator. You have a List<Integer> scores containing test scores. Using a Predicate<Integer> lambda, write code that creates a predicate called isPassing (score ≥ 60), then use a loop to print only the passing scores from the list [85, 42, 73, 58, 91, 60].
PROBLEM 5 — CRITICAL THINKING
A student writes the following lambda: Comparator<String> comp = (String a, String b) -> { a.length() - b.length(); }; This code does not compile. Identify the error, explain why it fails, and provide two different ways to fix it.

Lesson Summary

A lambda expression is a concise, anonymous function in Java that uses the arrow operator (->) to separate its parameters from its body. Introduced in Java 8, lambdas replace verbose anonymous inner classes and can only be used where Java expects a functional interface — an interface with exactly one abstract method. Key syntax rules include: single-parameter lambdas can skip parentheses, single-expression bodies auto-return their result, and multi-line bodies require curly braces with an explicit return statement.

Common functional interfaces include Predicate (testing conditions), Function (transforming values), Consumer (performing actions), Supplier (producing values), and Comparator (ordering objects). Lambdas are ideal for short, one-time logic; for complex or reusable behavior, named methods are preferred. Mastering lambda syntax prepares you for method references and the Stream API, which chain lambdas together for powerful data processing.

Varsity Tutors • Java • Lambda Expressions — Write basic lambda expressions