What Are Java Method References And Kinds Of Method References Available?
Tags: java, programming, beginners, tutorial
Published: 2022-03-12 04:41:19

## Method References

Method reference operator `::` is used to refer to the methods of functional interface. It is a compact and easy form of the lambda expression.

Lambda expressions are used to create anonymous methods.

Most of the time, we do some operations inside the lambda expression. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it’s often clearer to refer to the existing method by name.

So, whenever you are using a lambda expression to refer to a method, you can also do the same using a method reference. Replace the lambda expression with method reference and it works!

Method references allow you to do this. They are compact each-to-read lambda expressions for methods that already have a name.

Method reference is a wonderful feature introduced in Java 8. Apart from taking advantage of functional programming, one of the biggest advantages of using a Method Reference is it minimizes the number of lines of code even more than lambda expressions.

> Method references are a special type of lambda expression. They’re often used to create simple lambda expressions by referring to existing methods.

### Example 01: Uppercase Strings

```java
import java.util.Arrays;
import java.util.List;

class Main {
  public static void main(String[] args) {
    List<String> fruits = 
      Arrays.asList("Apple", "Banana", "guava", "grapes");

    fruits.stream()
      .map(String::toUpperCase)
      .forEach(System.out::println);
    }
}
```

We could have used lambda expression inside the terminal operation `.forEach(...)` like below.

```java
fruits.stream()
  .map(String::toUpperCase)
  .forEach(fruit -> System.out.println(fruit));
```

But, method reference syntaxes are clean and simple. The above lambda expression syntax is refactored with method reference as follows.

```java
    .forEach(System.out::println);
```

### Explanation
Let us see in detail what we are trying to achieve in the above snippet.

1. We have a list of fruits.

2. Chained with `.stream()`, so the collection of `String` objects gets converted into `Stream` of String objects.

3. Now, we need to chain `.stream()` with **intermediate operations**, such as `.map(...)` which makes use of **Method Reference**, `String::toUpperCase` to uppercase all the stream elements.

4. At last we chained it with a **terminal operation** `.forEach(...)` which also uses a Method Reference to print the data.

To understand what does intermediate and terminal operations mean in streams API, follow these hashnode articles for a better understanding.

- [Introduction To Java Streams API](https://dev.to/ggorantala/introduction-to-java-streams-api-1d05).

- [How Does Streams API Work? A Deep Dive on Stream Operation Flow](https://dev.to/ggorantala/how-does-streams-api-work-a-deep-dive-on-streamoperation-flow-4e07).

## Lambda Expressions to Method References

Here are some examples of how we can replace the lambda expressions using method references.


![Lambda expressions to method references](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a8vkebk2av19mn6lr56q.png)

Following, we will discuss different kinds of method references, their uses, an example code snippet, and an explanation.

## Kinds of Method References

There are four kinds of method references.

1. Reference to static methods.

2. Reference to instance methods of particular objects.

3. Reference to an instance method of an arbitrary object of a particular type.

4. Reference to a constructor.

### Generic syntax

So, the generic syntax for all these kinds of method references is as follows.

```java
class/object::method
```

### 1. Reference to a static method

A static method reference refers to the static method for a class. We can use a method reference to directly call the static methods. The syntax for referencing a static method is as follows.

#### Syntax

This is a classic syntax, and it's the class name followed by the static method you are trying to refer to.

```java
className::staticMethodName
```
#### Code
An example code snippet that explains how static methods are called using method references.

`Book` POJO with a constructor, getters, and setters.

```java
class Book {
  String title;
  String author;
  Integer year;
  Integer copiesSoldInMillions;
  Double rating;
  Double costInEuros;

  public Book(String title, String author, Integer year, Integer copiesSoldInMillions, Double rating, Double costInEuros) {
    this.title = title;
    this.author = author;
    this.year = year;
    this.copiesSoldInMillions = copiesSoldInMillions;
    this.rating = rating;
    this.costInEuros = costInEuros;
  }

  public String getTitle() {
    return title;
  }

  public Double getRating() {
    return rating;
  }

  @Override
  public String toString() {
    return "Book{" +
      "title='" + title + '\'' +
      ", author='" + author + '\'' +
      ", year=" + year +
      ", copiesSoldInMillions=" + copiesSoldInMillions +
      ", rating=" + rating +
      ", costInEuros=" + costInEuros +
      '}';
  }
}
```

`BookDatabase` for dummy data injection.

```java
import java.util.Arrays;
import java.util.List;

public class BookDatabase {
  public static List<Book> getAllBooks() {
    return Arrays.asList(
      new Book("Don Quixote", "Miguel de Cervantes", 1605, 500, 3.9, 9.99),
      new Book("A Tale of Two Cities", "Charles Dickens", 1859, 200, 3.9, 10.0),
      new Book("The Lord of the Rings", "J.R.R. Tolkien", 2001, 150, 4.0, 12.50),
      new Book("The Little Prince", "Antoine de Saint-Exupery", 2016, 142, 4.4, 5.0),
      new Book("The Dream of the Red Chamber", "Cao Xueqin", 1791, 100, 4.2, 10.0)
    );
  }
}
```
Following is our `BookApplication` class that does the imperative programming or mutations on book variable inside for-loop using static method reference.

```java
import java.util.List;

public class BookApplication {

  public static int compareByTitle(Book first, Book second) {
    return first.getTitle().compareTo(second.getTitle());
  }

  public static int compareByRating(Book first, Book second) {
    return first.getRating().compareTo(second.getRating());
  }

  public static void main(String[] args) {
    List<Book> books = BookDatabase.getAllBooks();

    System.out.println("SORT BASED ON RATINGS: ");
    books.sort(BookApplication::compareByRating);
    books.stream()
      .map(book -> book.getTitle() + " -> " + book.getRating())
      .forEach(System.out::println);

    System.out.println("---------");

    System.out.println("SORT BASED ON TITLES: ");
    books.sort(BookApplication::compareByTitle);
    books.stream()
      .map(book -> book.getTitle() + " -> " + book.getRating())
      .forEach(System.out::println);
  }
}
```

#### Output:
Above code, snippet outputs the following on console.

```java
SORT BASED ON RATINGS: 
Don Quixote -> 3.9
A Tale of Two Cities -> 3.9
The Lord of the Rings -> 4.0
The Dream of the Red Chamber -> 4.2
The Little Prince -> 4.4
---------
SORT BASED ON TITLES: 
A Tale of Two Cities -> 3.9
Don Quixote -> 3.9
The Dream of the Red Chamber -> 4.2
The Little Prince -> 4.4
The Lord of the Rings -> 4.0
```

### 2. Reference to an instance method of a particular object

The following is an example of a reference to an instance method of a particular object:

#### Syntax:
This is another syntax that uses instances of a particular object followed by the static method you are trying to refer to.

```java
object::staticMethodName
```

#### Code
An example code snippet that explains how static methods are called using method references.

> For simplicity, I am not duplicating `Book` and `BookDatabase` classes here, refer to them in the above example.

So, let's directly jump into the `BookApplication` class.

```java
import java.util.List;

public class BookApplication {

  public static void main(String[] args) {
    List<Book> books = BookDatabase.getAllBooks();

    BookApplication bookApplication = new BookApplication();

    System.out.println("SORT BASED ON RATINGS");
    books.sort(bookApplication::compareByRating);
    books.stream()
      .map(book -> book.getTitle() + " -> " + book.getRating())
      .forEach(System.out::println);

    System.out.println();

    System.out.println("SORT BASED ON TITLES: ");
    books.sort(bookApplication::compareByTitle);
    books.stream()
      .map(book -> book.getTitle() + " -> " + book.getRating())
      .forEach(System.out::println);
  }

  public int compareByTitle(Book first, Book second) {
    return first.getTitle().compareTo(second.getTitle());
  }

  public int compareByRating(Book first, Book second) {
    return first.getRating().compareTo(second.getRating());
  }
}
```

#### Output:

Above code, snippet outputs the following on console.

```java
SORT BASED ON RATINGS
Don Quixote -> 3.9
A Tale of Two Cities -> 3.9
The Lord of the Rings -> 4.0
The Dream of the Red Chamber -> 4.2
The Little Prince -> 4.4

SORT BASED ON TITLES: 
A Tale of Two Cities -> 3.9
Don Quixote -> 3.9
The Dream of the Red Chamber -> 4.2
The Little Prince -> 4.4
The Lord of the Rings -> 4.0
```

The method reference `bookApplication::compareByRating` invokes the method `compareByRating` that is part of the object `bookApplication`. The JRE infers the method type arguments, which in this case are (`Book book`).

The above simple explanation is the same for this method reference `bookApplication::compareByTitle`.

### 3. Reference to an instance method of an arbitrary object of a particular type.

The following is an example of a reference to an instance method of an arbitrary object of a particular type.

#### Code

##### Approach 01

```java
import java.util.Arrays;
import java.util.List;

class Main {
  public static void main(String[] args) {
    List<String> fruits = 
        Arrays.asList("Banana", "Grapes", "guava", "apples");
    fruits.sort(String::compareToIgnoreCase);
    fruits.forEach(System.out::println);
  }
}
```

##### Output:

```java
apples
Banana
Grapes
guava
```

The equivalent lambda expression for the method reference `String::compareToIgnoreCase` would have the formal parameter list `(String a, String b)`, where `a` and `b` are arbitrary names used to better describe this example. The method reference would invoke the method `a.compareToIgnoreCase(b)`.

Similarly, the method reference `String::concat` would invoke the method `a.concat(b)`.

##### Approach 02

```java
import java.util.Arrays;
import java.util.List;

class Main {
  public static void main(String[] args) {
    List<Integer> numbers = 
      Arrays.asList(11, 4, 2, 8, 9, 10, 32, 22, 20, 17);
    
    numbers.stream()
      // .sorted((a, b) -> a.compareTo(b)) lambda way
        .sorted(Integer::compareTo) 
        .forEach(s -> System.out.print(s + " "));
  }
}
```

##### Output:
```java
2 4 8 9 10 11 17 20 22 32
```

### 4. Reference to a Constructor

Constructor references are specialized forms of method references that refer to the constructors of a class. They can be created using the className and the keyword new.

#### Syntax
```java
className::new
```

#### Code

```java
public class BookApplication {
  public static void main(String[] args) {
    BookService bookService = Book::new;
    Book book = bookService.getBook(
      "The Little Prince",
      "Antoine de Saint-Exupery",
      2016, 142,
      4.4,
      5.0);

    System.out.println(book);
  }
}
```

#### Output:
```java
Book{title='The Little Prince', author='Antoine de Saint-Exupery', year=2016, copiesSoldInMillions=142, rating=4.4, costInEuros=5.0}
```

This wraps everything you need to know about **Method References** in **Java**. Happy Coding 🤩.

## Read More

1. [Introduction To Java Streams API](https://dev.to/ggorantala/introduction-to-java-streams-api-1d05)

2. [How Does Streams API Work? A Deep Dive on Stream Operation Flow](https://dev.to/ggorantala/how-does-streams-api-work-a-deep-dive-on-streamoperation-flow-4e07)

3. [Functional Programming And Programming Paradigms in Java](https://dev.to/ggorantala/functional-programming-and-programming-paradigms-in-java-323f)

4. [Imperative And Declarative Styles Of Programming](https://dev.to/ggorantala/imperative-and-declarative-styles-of-programming-186d)