Java 8 Method References

Last Updated : 8 Oct 2026

Java 8 introduces a new feature called method reference. Method reference is used to refer method of functional interface. It is compact and easy form of lambda expression. Each time when we use lambda expression for referring a method, we can replace lambda expression with method reference.

In this chapter, we will learn about Java Method References, their types (static, instance, and constructor), syntax, and how to use them with functional interfaces through practical examples.

What is Java Method Reference?

A method reference is a shorthand notation used to call a method by referring to it directly using the :: operator. It is a compact alternative to lambda expressions when the lambda simply invokes an existing method.

Types of Method References

In Java, there are four main types of method references introduced in Java 8:

  1. Static Method Reference
  2. Instance Method Reference of a Particular Object
  3. Instance Method Reference of an Arbitrary Object
  4. Constructor Reference

1) Static Method Reference

We can refer to static method defined in the class. It is used When a lambda expression just calls a static method. Following is the syntax and example which describe the process of referring static method in Java.

Syntax:

ClassName::staticMethodName

For example,

list.forEach(Math::abs); 
// Equivalent to: n -> Math.abs(n)

Example

interface Sayable{  
    void say();  
}  
public class Main {  
    public static void saySomething() {  
        System.out.println("Hello, this is static method.");  
    }  
    public static void main(String[] args) {  
        // Referring static method  
        Sayable sayable = Main::saySomething;  
        // Calling interface method  
        sayable.say();  
    }  
}  
Compile and Run

Output:

Hello, this is static method.

Example:

In the following example, we are using predefined functional interface Runnable to refer static() method.

Java

public class Main {  
    public static void ThreadStatus(){  
        System.out.println("Thread is running...");  
    }  
    public static void main(String[] args) {  
        Thread t2=new Thread(Main::ThreadStatus);  
        t2.start();       
    }  
}  
Compile and Run

Output:

Thread is running...

Example:

We can also use predefined functional interface to refer methods. In the following example, we are using BiFunction interface and using it's apply() method.

Java

import java.util.function.BiFunction;  
class Arithmetic {  
public static int add(int a, int b){  
return a+b;  
}  
}  
 class Main {  
public static void main(String[] args) {  
BiFunction<Integer, Integer, Integer>adder = Arithmetic::add;  
int result = adder.apply(10, 20);  
System.out.println(result);  
}  
}
Compile and Run

Output:

30

Example:

We can also override static methods by referring methods. In the following example, we have defined and overloaded three add methods.

Java

import java.util.function.BiFunction;  
class Arithmetic {  
public static int add(int a, int b){  
return a+b;  
}  
public static float add(int a, float b){  
return a+b;  
}  
public static float add(float a, float b){  
return a+b;  
}  
}  
class Main {  
public static void main(String[] args) {  
BiFunction<Integer, Integer, Integer>adder1 = Arithmetic::add;  
BiFunction<Integer, Float, Float>adder2 = Arithmetic::add;  
BiFunction<Float, Float, Float>adder3 = Arithmetic::add;  
int result1 = adder1.apply(10, 20);  
float result2 = adder2.apply(10, 20.0f);  
float result3 = adder3.apply(10.0f, 20.0f);  
System.out.println(result1);  
System.out.println(result2);  
System.out.println(result3);  
}  
}
Compile and Run

Output:

30
30.0
30.0

2) Reference to an Instance Method of a Particular Object (Bound Reference)

Like static methods, we can refer instance methods also. It is used when we already have an object and want to use its method.

Syntax:

instance::instanceMethodName

For example,

System.out::println; 
// Equivalent to: s -> System.out.println(s)

Example:

In the following example, we are referring non-static methods. We can refer methods by class object and anonymous object.

Java

interface Sayable{  
    void say();  
}  
public class Main {  
    public void saySomething() {  
        System.out.println("Hello, this is non-static method.");  
    }  
    public static void main(String[] args) {  
        Main methodReference = new Main(); // Creating object  
        // Referring non-static method using reference  
            Sayable sayable = methodReference::saySomething;  
        // Calling interface method  
            sayable.say();  
            // Referring non-static method using anonymous object  
            Sayable sayable2 = new Main()::saySomething; // You can use anonymous object also  
            // Calling interface method  
            sayable2.say();  
    }  
}
Compile and Run

Output:

Hello, this is non-static method.
Hello, this is non-static method

Example:

In the following example, we are referring instance (non-static) method. Runnable interface contains only one abstract method. So, we can use it as functional interface.

Java

public class Main {  
    public void printnMsg(){  
        System.out.println("Hello, this is instance method");  
    }  
    public static void main(String[] args) {  
    Thread t2=new Thread(new Main()::printnMsg);  
        t2.start();       
    }  
}  
Compile and Run

Output:

Hello, this is instance method

Example:

In the following example, we are using BiFunction interface. It is a predefined interface and contains a functional method apply(). Here, we are referring add method to apply method.

Java

import java.util.function.BiFunction;  
class Arithmetic {  
public int add(int a, int b){  
return a+b;  
}  
}  
class Main {  
public static void main(String[] args) {  
BiFunction<Integer, Integer, Integer>adder = new Arithmetic()::add;  
int result = adder.apply(10, 20);  
System.out.println(result);  
}  
}
Compile and Run

Output:

30

3) Reference to an Instance Method of an Arbitrary Object (Unbound Reference)

It is used when the first parameter of the lambda provides the instance.

Syntax:

ClassName::instanceMethodName

For example,

String::toUpperCase; 
// Equivalent to: s -> s.toUpperCase()

Example

In the following example, String::toUpperCase is an unbound method reference. It means that for each element in the stream (a String), call its toUpperCase() method. The compiler treats it as s -> s.toUpperCase().

It works because the first parameter of the functional interface (Function<T,R>) provides the instance (s).

Java

import java.util.Arrays;
import java.util.List;
public class Main {
    public static void main(String[] args) {
        // Create a list of strings
        List<String> names = Arrays.asList("Jeep", "Truck", "Bus", "Car");
        // Using method reference to an instance method of an arbitrary object
        // String::toUpperCase means: s -> s.toUpperCase()
        names.stream()
             .map(String::toUpperCase)   // Unbound reference
             .forEach(System.out::println);
    }
}
Compile and Run

Output:

JEEP
TRUCK
BUS
CAR

4) Reference to a Constructor

We can refer a constructor by using the new keyword. It is used when a lambda creates a new object. Here, we are referring constructor with the help of functional interface.

Syntax:

ClassName::new  

For example,

Supplier<List<String>> supplier = ArrayList::new;
// Equivalent to: () -> new ArrayList<String>()

Example

In this example, a constructor reference (Message::new) is used to create an object of the Message class through a functional interface in a concise and readable way.

Java

interface Messageable {  
    Message getMessage(String msg);  
}  
class Message {  
    Message(String msg){  
        System.out.print(msg);  
    }  
}  
public class Main {  
    public static void main(String[] args) {  
        Messageable hello = Message::new;  
        hello.getMessage("Hello");  
    }  
}
Compile and Run

Output:

Hello

Important Points to Remember

  1. Method Reference is a shorthand for Lambda expressions when we are only calling an existing method.
  2. Method references require functional interfaces — interfaces with a single abstract method (like Runnable, Callable, Consumer, BiFunction, etc.).
  3. Method signatures must match — the method we are referencing must be compatible with the functional method's parameter and return types.
  4. We can reference both user-defined and built-in methods — method references work with any accessible method that fits the required signature.
  5. Overloaded methods can be referenced, and the compiler resolves the correct one based on the context.