Constructor References in Java 8
Fast recall
Quick revision
Core answer
ClassName::new to create objects through a compatible functional interface. For example, Supplier factory = User::new selects a no-argument constructor, while Function factory = User::new selects a constructor compatible with one String argument. The target functional-interface type provides the context used to select the constructor.Whether you know all four method reference types including constructor references, which are less intuitive than the others.
Ignoring the target functional-interface type, which supplies the argument and return types used to resolve a constructor reference.
Demonstrate a factory pattern example using constructor references, showing how they enable flexible object creation without explicit new keywords scattered throughout code.
Interview-ready guide
Interview answer
A constructor reference in Java 8 uses the ClassName colon colon new syntax to reference a constructor as if it were a method.
It lets you pass object creation logic around as a functional interface instead of explicitly calling new every time you need an instance. The functional interface you're using determines which constructor overload gets called. If you use Supplier with User colon colon new, that calls the no-arg constructor because Supplier has no parameters.
If you use Function with String comma User and User colon colon new, it calls the constructor that takes one String parameter. The main use case is factory patterns. Instead of scattering new User calls throughout your code, you can pass User colon colon new to methods that need to create users.
This makes your code more flexible because you can swap out the implementation by changing the constructor reference without touching all the places that use it. A really common practical example is with Stream dot collect. When you want a specific collection type, you write stream dot collect with Collectors dot to collection and pass the constructor reference like TreeSet colon colon new.
That tells the collector what type of collection to create for storing the results. Another place you see this is array creation with streams. If you write stream dot to array without arguments, you get an Object array.
But if you pass String array colon colon new, you get back a properly typed String array. The key thing to remember is that the parameter types and count of your functional interface have to exactly match one of the class's constructors. If there's no matching constructor, it won't compile.
This is one of those features that feels weird at first but becomes really natural once you start using it in real code.
Constructor References in Java 8
Direct Answer
A constructor reference uses ClassName::new to create objects through a compatible functional interface. For example, Supplier<User> factory = User::new selects a no-argument constructor, while Function<String, User> factory = User::new selects a constructor compatible with one String argument. The target functional-interface type provides the context used to select the constructor.
Code Example
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
record User(String username, String email) {
// Constructor overloads for demonstration
public User(String username) {
this(username, username + "@example.com");
}
}
public class ConstructorReferenceDemo {
public static void main(String[] args) {
// No-arg constructor reference with Supplier
Supplier<List<String>> listFactory = ArrayList::new;
List<String> list1 = listFactory.get();
// Single-arg constructor reference with Function
Function<String, User> userFactory = User::new; // calls User(String)
User alice = userFactory.apply("alice");
// Two-arg constructor with BiFunction
BiFunction<String, String, User> fullUserFactory = User::new;
User bob = fullUserFactory.apply("bob", "bob@company.com");
// Practical use: custom collection type in Stream.collect()
var names = List.of("charlie", "alice", "bob", "alice");
Set<String> uniqueSorted = names.stream()
.collect(Collectors.toCollection(TreeSet::new)); // TreeSet maintains sorted order
// Array constructor reference
String[] array = names.stream().toArray(String[]::new);
}
}
Common Mistakes & Pitfalls
- Missing constructor:
Supplier<User> factory = User::newfails whenUserhas no accessible no-argument constructor. - Ignoring target typing:
Function<String, User>normally selectsUser(String)even when other one-argument constructors exist. Ambiguity occurs only if the target types still leave more than one applicable overload. - Forgetting the typed-array form: no-argument
stream.toArray()returnsObject[]; usestream.toArray(String[]::new)when aString[]is required.
Check your understanding
Answer these without looking back at the article.
- How does the compiler choose which constructor to use for a constructor reference?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.