Over

120,000

Worldwide

Saturday - Sunday CLOSED

Mon - Fri 8.00 - 18.00

Call us

 

Java 8 Method References

Java 8 Method References

Double colon (: 🙂 operator

Starting from Java 8, there was introduced a new feature, called method reference. In short, it is a special type of lambda expressions and often is used to create simple lambda expressions by referencing existing methods. Each time you can just replace your lambda expression with method reference.

Of course, this feature is being widely used because of its benefits. One of the benefits is that by using method references, you make your code shorter, which can become more readable.

➢ For example, let us have an output like this.

str -> System.out.println(str)

This line can be replaced with a method reference, and we can write it.

System.out::println

Here the :: operator separates the Class or the Object from the method.

➢ Another example we can discuss now.

Here we have an anonymous class, which is just printing a list.

List<Integer> myList = Arrays.asList(1, 2, 3, 4);

//this is an anonymous class

myList.forEach(new Consumer<Integer>() {

@Override

public void accept(Integer a) {

System.out.println(a);

}

});

In its turn, this anonymous class can be replaced with Lambda expressions.

List<Integer> myList2 = Arrays.asList(1, 2, 3, 4);

myList2.forEach(a -> System.out.println(a));

This Lambda expressions can be changed into Method references.

List<Integer> myList3 = Arrays.asList(1, 2, 3, 4);

myList3.forEach(System.out::println);

So, this is the hierarchy.

Anonymous Class -> Lambda expression -> Method Reference

The method references can be of four types:

• Static methods (Class::staticMethodName)

• Instance methods of particular objects (object::instanceMethodName)

• Instance methods of an arbitrary object of a particular type (Class::methodName) • Constructor (Class::new)

So, now let us discuss each of them and look at examples.

• Static Method References

When calling a static method with its containing class before, you simply refer a static method defined in that class. The syntax that describes this process of referring is below:

ContainingClass::staticMethodName  

Now let us define a class and refer its static method from another class, and describe this process. Here is a class with its static method:

public class A {

public static void duplicateNumber(int num) {

int duplicate = num * 2;

System.out.println(duplicate);

}

}

And below we are using static utility method:

public class B {

public static void main(String[] args) {

List<Integer> integerList = new LinkedList<>();

integerList.add(3);

integerList.add(9);

integerList.add(8);

integerList.add(14);

//anonymous class

integerList.forEach(new Consumer<Integer>() {

@Override

public void accept(Integer integer) {

A.duplicateNumber(integer);

}

});

//lambda expression

integerList.forEach((a) -> A.duplicateNumber(a));

//method reference

integerList.forEach(A::duplicateNumber);

}

}

The result for this code will be:

6

18

16

28

So the method references always utilize the :: operator.

• Instance methods of particular objects

When you call a method from a particular instantiated object using the reference variable of the object, you just reference the method.

Here is the syntax describing this process:

containingObject::instanceMethodName

Now we can look at an example of referring the instance method.

Here is a Person class:

public class Person {

private String name;

private String surname;

private int age;

// Constructor, getters and setters

@Override

public String toString() {

return “Name: ” + name + “, Surname: ” + surname + “, Age: ” + age;

}

public int compareTo(Person person) {

if (this.age <= person.age) {

return 1;

} else {

return 1;

}

}

}

And now we define OurComparator:

public class OurComparator {

public int compareEntities(Person per1, Person per2) {

return per1.compareTo(per2);

}

}

And finally we create a list and sort it:

public static void main(String[] args) {

Person per1 = new Person(“Gayane”, “Zakoyan”, 20);

Person per2 = new Person(“Harut”, “Aristakesyan”, 22);

Person per3 = new Person(“Ann”, “Adams”, 45);

Person per4 = new Person(“John”, “Simons”, 7);

ArrayList<Person> people = new ArrayList<>();

people.add(per1);

people.add(per2);

people.add(per3);

people.add(per4);

// Initializing our CustomComparator

OurComparator ourComparator = new OurComparator();

//anonymous class

people.sort(new Comparator<Person>() {

@Override

public int compare(Person person, Person person2) {

return ourComparator.compareEntities(person, person2);

}

});

// lambda expression

Collections.sort(people, (obj1, obj2) -> ourComparator.compareEntities(obj1, obj2));

// Instead of making a call to an arbitrary Person

// we’re now providing an instance and its method

//method reference

Collections.sort(people, ourComparator::compareEntities);

System.out.println(people);

}

The result is:

[Name: Ann, Surname: Adams, Age: 45, Name: Harut, Surname: Aristakesyan, Age: 22, Name: Gayane, Surname: Zakoyan, Age: 20, Name: John, Surname: Simons, Age: 7]

A difference between these is that by OurComparator we can add many functionalities for comparison and take away from the class.

• Instance methods of an arbitrary object of a particular type

This type of method referencing is similar to the one discussed above, but here we do not have to create an object to perform the comparison.

Here is the syntax for this type of method referencing:

Class::methodName

Now let us create an Integer list that we are going to sort.

List<Integer> integerList = new ArrayList<>();

integerList.add(9);

integerList.add(15);

integerList.add(3);

integerList.add(7);

integerList.add(1);

integerList.add(18);

Here if we use a classic lambda expression, both of the parameters should be passed, but if we use a method reference it will look like this:

//anonymous class

integerList.stream().sorted(new Comparator<Integer>() {

@Override

public int compare(Integer integer, Integer integer2) {

return integer.compareTo(integer2);

}

});

//lambda expression

integerList.stream()

.sorted((a, b) -> a.compareTo(b));

//method reference

integerList.stream()

.sorted(Integer::compareTo);

So, an arbitrary object of a particular type means a reference to an instance method from some type. The program knows that it can invoke this compareTo method of Integer, so it can take the reference and any object of that type and be guaranteed the method exists.

Let us look at another example.

String[] strArray = {“John”, “Ann”, “Ellen”, “Barbara”,

“Patricia”, “Mary”, “Mike”, “Rose”};

//lambda expression

Arrays.sort(strArray, (a, b) -> a.compareToIgnoreCase(b));

//method reference

Arrays.sort(strArray, String::compareToIgnoreCase);

Here we see the same thing. The program is guaranteed that a method of this String type exists and takes parameter any object of this type.

So, here the method reference is easier to understand and read.

• Constructor

We can reference a constructor of a class in the same way that we referenced a static method. But its syntax will look like this:

ClassName::new

Let us look at this example.

We have a class Letter:

class Letter {

Letter(String let) {

System.out.print(let);

}

}

An interface with a method returning type of the class above:

interface Writing {

Letter getLetter(String let);

}

And here we can see the usage of the Constructor reference:

public class ClassA {

public static void main(String[] args) {

//lambda expression

Writing hello = (a) -> new Letter(a);

hello.getLetter(“Hello”);

//method reference

Writing hello1 = Letter::new;

hello1.getLetter(“Hello1”);

}

}

So, in conclusion the Method References are just used for referencing a method in their call. Using them, your code will be more concise and easy to read.

Leave a Reply

Your email address will not be published. Required fields are marked *

Working Hours

  • Monday 9am - 6pm
  • Tuesday 9am - 6pm
  • Wednesday 9am - 6pm
  • Thursday 9am - 6pm
  • Friday 9am - 6pm
  • Saturday Closed
  • Sunday Closed