Back to Method References
Q3Question 3 of 5

Rewrite a lambda e -> e.getName() as a method reference Employee::getName

Key Concepts
  • When a lambda does nothing but call one method on its parameter, it can be replaced with a method reference
  • e -> e.getName() becomes Employee::getName (unbound instance-method reference)
  • The lambda's parameter becomes the receiver of getName
  • Both forms are compiled to the same bytecode; method references are syntactic sugar
  • Method references only apply to pure delegation: no extra arguments, no logic, no null checks
  • Use method references for readability; keep explicit lambdas when any logic is involved

Definition

e -> e.getName() is exactly Employee::getName: the lambda parameter becomes the method receiver.
  • An unbound instance-method reference Type::method refers to a method without a specific instance.
  • The lambda parameter is supplied as the receiver at call time.
  • Employee::getName satisfies Function just like e -> e.getName().
  • Both produce identical bytecode; the reference is syntactic sugar.
  • Only applies when the lambda body is a single method call on its own parameter.

Instead of writing a sticky note saying 'take the employee and ask for the name', Priya at the National Bank of India just points at the 'getName' skill directly. The pointing is the method reference.

Understanding the Concepts

What is an unbound instance-method reference?

Employee::getName refers to the getName method without binding it to a specific object. The instance is supplied later as the first argument when the functional interface is invoked.

JAVA
package com.bank.hr;

import java.util.*;
import java.util.stream.Collectors;
import java.util.function.Function;

public class MethodRefDemo {
    public static void main(String[] args) {
        List<Employee> employees = List.of(
            new Employee("Rajesh", "Loans"),
            new Employee("Priya",  "IT"),
            new Employee("Amit",   "Finance")
        );

        // Lambda
        List<String> namesLambda = employees.stream()
            .map(e -> e.getName())
            .collect(Collectors.toList());

        // Method reference (equivalent)
        List<String> namesRef = employees.stream()
            .map(Employee::getName)
            .collect(Collectors.toList());

        System.out.println(namesRef);
    }
}
TEXT
[Rajesh, Priya, Amit]

How does the compiler match the reference?

The compiler matches Employee::getName to the target functional interface. If map expects a Function, and getName is an instance method of Employee returning String with no arguments, the match succeeds.

DIAGRAM
| Lambda | Method reference | Target interface |
|---|---|---|
| e -> e.getName() | Employee::getName | Function<Employee, String> |
| e -> e.getSalary() | Employee::getSalary | Function<Employee, BigDecimal> |
| e -> e.toString() | Employee::toString | Function<Employee, String> |

When should you keep the lambda?

Method references only work for pure delegation. If you need any extra logic, keep the lambda.

JAVA
// Method reference: pure delegation
.map(Employee::getName)

// Lambda required: null check
.map(e -> e.getName() != null ? e.getName() : "UNKNOWN")

// Lambda required: transformation
.map(e -> e.getName().toUpperCase())

// Lambda required: multiple fields
.map(e -> e.getName() + " (" + e.getDepartment() + ")")

What are the four types of method references?

| Type | Syntax | Example |
|---|---|---|
| Static method | Type::staticMethod | Integer::parseInt |
| Unbound instance | Type::instanceMethod | Employee::getName |
| Bound instance | instance::method | System.out::println |
| Constructor | Type::new | Employee::new |

What are common mistakes?

Mistake: using a method reference when extra logic is needed.

JAVA
// WRONG: cannot add null check in a method reference
.map(Employee::getName)  // NPE if employee is null

// CORRECT: use lambda for null safety
.filter(Objects::nonNull)
.map(Employee::getName)

What should a senior engineer know?

  • Method references improve readability by naming the operation rather than describing it.
  • They compile to the same bytecode as lambdas; there is no performance difference.
  • Choosing between them is a clarity decision, not a style rule.
  • Overusing method references where logic is involved actually hurts readability.

What are common interview follow-up questions?

  • "What is the difference between Employee::getName and someEmployee::getName?" The first is unbound (parameter is receiver); the second is bound (specific object is the receiver).
  • "Can a method reference throw?" Yes, if the underlying method throws.
  • "Can you use method references with overloaded methods?" The compiler picks the overload matching the target functional interface.

Visual Overview

DIAGRAM
  Lambda form:              Method reference form:
  e -> e.getName()          Employee::getName
       │                         │
       │  Compiler sees:         │  Compiler sees:
       │  parameter e,           │  unbound method getName
       │  calls getName on e     │  on type Employee
       ▼                         ▼
  Function<Employee, String>    Function<Employee, String>
       │                         │
       └──── identical bytecode ─┘

Key Takeaway

When a lambda does nothing but call a single method on its parameter, rewrite it as an unbound instance-method reference. The lambda e -> e.getName() becomes Employee::getName, where the lambda's parameter becomes the method's receiver. Both satisfy the same functional interface and compile to identical bytecode.

At the National Bank of India, the codebase uses method references wherever a stream maps employees to their names, departments, or salaries, because the reference names the operation directly and is easier to read at a glance.

The key rule is that method references only apply to pure delegation: one method call on the parameter, no extra logic, no null checks. The moment you need to transform, combine, or guard, keep the explicit lambda.

Remember one sentence: Employee::getName replaces e -> e.getName() when the lambda is pure delegation, and the parameter becomes the receiver.

---

Share
Use ← → arrow keys to navigate