In the previous post of the Towards Functional Java series, we saw how to create a reference to a method implementation using lambda expressions and functional interfaces, passing it as an argument to methods in the same way we are used to pass object references.
Note: to try out the examples in this post, you need a Java 8 development environment. If you do not have one, you can follow this tutorial to set one up.
In the following JUnit test, we implement the functional interface Comparator
@Test
public void lambdaExpressionTest() {
Comparator<String> comp = (str1, str2) ->
Integer.compare(str1.length(), str2.length());
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("abcdef");
list.add("ab");
Collections.sort(list, comp);
assertTrue(list.get(0).equals("ab"));
}
Now, suppose the above functionality was already provided by a method of an existing class, as in the following example:
public class AlternativeStringComparison {
public int compareByLength(String str1, String str2) {
return Integer.compare( str1.length(), str2.length());
}
}
You can refer to the compareByLength method directly using the following notation:
@Test
public void lengthComparisonTest() {
AlternativeStringComparison comp = new AlternativeStringComparison();
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("abcdef");
list.add("ab");
Collections.sort(list, comp::compareByLength);
assertTrue(list.get(0).equals("ab"));
}
The expression comp::compareByLength is called a method reference. In this case we are creating a reference to an instance method, using the notation object::instanceMethodName.
If the instance method is defined by the same class of the receiver object, you can use the notation Class::instanceMethodName. For example, the String class defines an instance method to perform a case-insensitive string comparison. See the API doc:
You can create a reference to it as follows:
@Test
public void caseInsensitiveComparisonTest() {
List<String> list = new ArrayList<String>();
list.add("bobby");
list.add("Andrew");
list.add("john");
Collections.sort(list, String::compareToIgnoreCase);
assertTrue(list.get(0).equals("Andrew"));
}
Likewise, it is possible to create a reference to a static method with the notation Class::staticMethodName. Consider the following class:
public class AlternativeStringComparison {
public static int compareByLen(String str1, String str2) {
return Integer.compare( str1.length(), str2.length());
}
}
You can create a reference to its static method as follows:
@Test
public void staticLengthComparisonTest() {
List<String> list = new ArrayList<String>();
list.add("abcd");
list.add("abcdef");
list.add("ab");
Collections.sort(list, AlternativeStringComparison::compareByLen);
assertTrue(list.get(0).equals("ab"));
}
Constructor methods can be also referenced using the notation Class::new. We will look at practical applications of constructor references in a later post when discussing Java 8 streams.
In summary, four types of method references have been introduced in Java 8:
| Type | Notation | Notes |
|---|---|---|
| Reference to a bound instance method | object::instanceMethodName | |
| Reference to an unbound instance method | Class::instanceMethodName | |
| Reference to a static method | Class::staticMethodName | |
| Reference to a constructor | Class::new |
In the next post we will look at more Java 8 functional features. Feel free to leave any comments or suggestions. Thank you for reading.
