Method References in Java
Method references are a shorthand notation for lambda expressions that call a single method, introduced in Java 8. They use the double colon :: operator to reference existing methods instead of writing full lambda expressions. Method references work with functional interfaces and make code more concise and readable when a lambda expression only calls one method without additional logic. There are four types: static method references, instance method references of particular objects, instance method references of arbitrary objects, and constructor references.
Interview Questions & Expert Answers
Section titled “Interview Questions & Expert Answers”1. What is a method reference and how is it related to lambda expressions?
Section titled “1. What is a method reference and how is it related to lambda expressions?”Your Answer:
A method reference is a shorthand syntax for lambda expressions that simply call an existing method without doing anything else. It uses the :: operator to reference methods by name and makes code more readable and concise.
Relationship: Method references are syntactic sugar for specific types of lambda expressions - those that only delegate to an existing method.
Example showing equivalence:
// Lambda expressionlist.forEach(s -> System.out.println(s));
// Equivalent method referencelist.forEach(System.out::println);Both do exactly the same thing, but the method reference is cleaner and more readable.
Key points:
- Method references work only with functional interfaces
- They reference methods by name without specifying arguments
- The arguments are automatically passed by the lambda expression context
- Use method references when your lambda only calls a single method without any transformation
If your lambda does more than just call a method (like transforming the argument first), you cannot use a method reference and must stick with lambda syntax.
2. What are the different types of method references in Java? (Static, instance, constructor, etc.)
Section titled “2. What are the different types of method references in Java? (Static, instance, constructor, etc.)”Your Answer:
There are four types of method references in Java :
1. Reference to a Static Method
- Syntax:
ClassName::staticMethodName - Example:
// Lambda: (a, b) -> Math.max(a, b)// Method reference:BinaryOperator<Integer> max = Math::max;2. Reference to an Instance Method of a Particular Object
- Syntax:
objectInstance::instanceMethodName - Refers to a method of a specific object you already have
- Example:
Greeter greeter = new Greeter();// Lambda: name -> greeter.greet(name)// Method reference:list.forEach(greeter::greet);3. Reference to an Instance Method of an Arbitrary Object of a Particular Type
- Syntax:
ClassName::instanceMethodName - Used when calling a method on any object of a specific class
- Example:
// Lambda: (s1, s2) -> s1.compareToIgnoreCase(s2)// Method reference:list.sort(String::compareToIgnoreCase);4. Reference to a Constructor
- Syntax:
ClassName::new - Creates new objects using the constructor
- Example:
// Lambda: name -> new Person(name)// Method reference:list.stream().map(Person::new).collect(Collectors.toList());The key difference between types 2 and 3: Type 2 uses a specific object instance, while Type 3 uses the class name and applies the method to objects passed in.
3. Can you give an example of replacing a lambda with a method reference using System.out::println?
Section titled “3. Can you give an example of replacing a lambda with a method reference using System.out::println?”Your Answer:
Here’s a complete example showing the transformation:
Before - Using Lambda Expression:
List<String> names = Arrays.asList("John", "Jane", "Bob");
// Approach 1: Traditional for loopfor (String name : names) { System.out.println(name);}
// Approach 2: Lambda expressionnames.forEach(s -> System.out.println(s));After - Using Method Reference:
List<String> names = Arrays.asList("John", "Jane", "Bob");
// Method reference - much cleanernames.forEach(System.out::println);Why this works:
forEachexpects aConsumer<T>functional interface- The lambda
s -> System.out.println(s)takes one argument and passes it directly toprintln() - Since we’re just delegating to an existing method without transformation, we can use
System.out::println
More examples with different data types:
// With integersList<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);numbers.forEach(System.out::println);
// With custom objectsList<Employee> employees = getEmployees();employees.forEach(System.out::println); // Calls toString() on each
// In streamsemployees.stream() .map(Employee::getName) .forEach(System.out::println);This is a reference to an instance method of a particular object - specifically the println method of the System.out object.
4. When would you prefer using a method reference instead of a lambda expression?
Section titled “4. When would you prefer using a method reference instead of a lambda expression?”Your Answer:
Use method references when:
1. Your lambda only calls a single method without any additional logic
// GOOD - Use method referencelist.forEach(System.out::println);
// DON'T use if lambda does morelist.forEach(s -> System.out.println("Name: " + s)); // Stick with lambda2. Readability improves significantly
// More readable with method referenceemployees.stream() .map(Employee::getName) .collect(Collectors.toList());
// Less readable with lambdaemployees.stream() .map(e -> e.getName()) .collect(Collectors.toList());3. The method signature matches perfectly
// Perfect match - use method referencelist.stream().map(String::toUpperCase)
// Constructor reference for object creationnames.stream().map(Person::new).collect(Collectors.toList());Stick with lambda expressions when:
1. You need to transform or modify arguments
// Lambda necessary - can't use method referencelist.stream().map(s -> s.substring(0, 3))2. You need to call multiple methods or add logic
// Lambda necessarylist.stream().filter(s -> s.length() > 5 && s.startsWith("A"))3. You need to pass different arguments than what’s provided
// Lambda necessarylist.forEach(s -> someMethod(s, additionalParam))Guidelines:
- Method references are generally preferred when applicable because they’re more concise and express intent clearly
- They reduce boilerplate code and make the code easier to read
- However, don’t force method references when lambdas are clearer
- If your IDE suggests converting a lambda to a method reference, it’s usually a good idea to follow that suggestion
Performance note: Method references and lambdas have the same performance characteristics - the choice is purely about readability and code style.