Definition
- A constructor reference
Type::newrefers to a constructor as a functional value. - The compiler matches the constructor whose parameter list fits the target functional interface.
Functionmatches a single-argument constructor.BiFunctionmatches a two-argument constructor.- Also used with toArray(Type[]::new) to build typed arrays.
Priya at the National Bank of India has a list of raw names and wants an employee record for each. Instead of writing 'take a name and build a new employee', she just points at the employee factory and feeds it names.
Understanding the Concepts
How do you use a constructor reference in a stream?
If Employee has a constructor taking a String name, Employee::new serves as Function
package com.bank.hr;
import java.util.*;
import java.util.stream.Collectors;
public class ConstructorRefDemo {
public static void main(String[] args) {
List<String> names = List.of("Rajesh", "Priya", "Amit");
// Lambda
List<Employee> lambda = names.stream()
.map(name -> new Employee(name))
.collect(Collectors.toList());
// Constructor reference (equivalent)
List<Employee> ref = names.stream()
.map(Employee::new)
.collect(Collectors.toList());
ref.forEach(e -> System.out.println(e.getName()));
}
}
Rajesh
Priya
Amit
How does the compiler select the right constructor overload?
The target functional interface determines which constructor overload is used.
| Target interface | Constructor matched |
|---|---|
| Function
| BiFunction
| Supplier
// Two-argument constructor
List<String[]> pairs = List.of(
new String[]{"Rajesh", "Loans"},
new String[]{"Priya", "IT"}
);
BiFunction<String, String, Employee> twoArg = Employee::new;
Employee e = twoArg.apply("Rajesh", "Loans");
How do you use a constructor reference with toArray?
Stream.toArray() without arguments returns Object[]. Pass an array constructor reference for a typed array.
Employee[] array = names.stream()
.map(Employee::new)
.toArray(Employee[]::new);
System.out.println(Arrays.toString(array));
When should you keep the lambda instead?
If construction requires validation, defaulting, or extra logic, a bare constructor reference has no room for it.
// Constructor reference: simple, no validation
.map(Employee::new)
// Lambda: needed for validation
.map(name -> {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("Name required");
}
return new Employee(name.strip());
})
// Static factory method: encapsulates validation
.map(Employee::create) // Employee.create(String) validates internally
What are common mistakes?
Mistake: ambiguous constructor overloads.
// If Employee has Employee(String) and Employee(Object),
// and the target is Function<String, Employee>,
// the compiler may report ambiguity.
// Fix: use an explicit lambda to resolve.
What should a senior engineer know?
- Constructor references pair naturally with map to turn raw data into domain objects.
- They assume the constructor alone fully and safely builds the object.
- When the construction needs validation, use a static factory method reference instead.
- toArray(Type[]::new) is the standard way to convert a stream to a typed array.
What are common interview follow-up questions?
- "What is the difference between Employee::new and () -> new Employee()?" Both create employees, but the first is a constructor reference and the second is a lambda. They compile similarly. - "Can you use constructor references with generics?" Yes: ArrayList::new creates ArrayList instances. - "How do you handle checked exceptions in a constructor reference?" Wrap in a method that catches, or use a custom functional interface that declares the exception.
Visual Overview
Stream<String> ["Rajesh", "Priya", "Amit"]
│
│ .map(Employee::new)
│
│ Compiler matches:
│ Employee(String name) ← one-arg constructor
▼
Stream<Employee>
[Employee(Rajesh), Employee(Priya), Employee(Amit)]
│
│ .toArray(Employee[]::new)
▼
Employee[] ← typed array
Key Takeaway
A constructor reference treats a constructor as a functional value. Employee::new matched against Function
At the National Bank of India, onboarding imports used Employee::new to lift raw holder names into domain objects, reading more cleanly than the equivalent lambda. Constructor references also pair with toArray(Employee[]::new) to produce typed arrays.
A bare constructor reference assumes the constructor alone fully builds the object. When validation or defaulting is needed, step back to a lambda or a static factory method.
Remember one sentence: Employee::new is a constructor reference that creates objects by matching the constructor overload to the target functional interface.
---