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.