An Overview of Method References
This overview of method references tackles their relationships to lambda expressions, their various uses, and what restrictions they need to follow.
Join the DZone community and get the full member experience.
Join For FreeMethod references are a feature of Java 8. They are effectively a subset of lambda expressions, because if a lambda expression can be used, then it might be possible to use a method reference, but not always. They can only be used to call a singular method, which obviously reduces the possible places they can be used, unless your code is written to cater for them.
It would be a good idea if you knew the notation for a method reference. In fact, you have probably already seen it assuming you read the title. If not then just look below.
Person::getName
The example above is the equivalent of writing person.getName(), where person is an instance of Person. Let me tell you a bit more about when you can use method references and show some examples as it makes a lot more sense with them.
Types of Method References
Type | Syntax | Method Reference | Lambda expression |
Reference to a static method | Class::staticMethod | String::valueOf | s -> String.valueOf(s) |
Reference to an instance method of a particular object |
instance::instanceMethod | s:toString | () -> “string”.toString() |
Reference to an instance method of an arbitrary object of a particular type |
Class:instanceMethod | String::toString | s -> s.toString() |
Reference to a constructor | Class::new | String::new | () -> new String() |
Reference to a Static Method
public class StaticMethodReference{
public static void main(String args[]) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Method reference
list.forEach(StaticMethodReference::print);
// Lambda expression
list.forEach(number -> StaticMethodReference.print(number));
// normal
for(int number : list) {
StaticMethodReference.print(number);
}
}
public static void print(final int number) {
System.out.println("I am printing: " + number);
}
}
Here, it calls the static method StaticMethodReference.print. This example is pretty simple. There is a static method, and for each element in the list, it calls this method using the element as the input.
Reference to an Instance Method of a Particular Object
public class ParticularInstanceMethodReference {
public static void main(String args[]) {
final List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
final MyComparator myComparator = new MyComparator();
// Method reference
Collections.sort(list, myComparator::compare);
// Lambda expression
Collections.sort(list, (a,b) -> myComparator.compare(a,b));
}
private static class MyComparator {
public int compare(final Integer a, final Integer b) {
return a.compareTo(b);
}
}
}
Here, it calls the instance method myComparator.compare, where myComparator is a particular instance of MyComparator.
Reference to an Instance Method of an Arbitrary Object of a Particular Type
public class ArbitraryInstanceMethodReference {
public static void main(String args[]) {
final List<Person> people = Arrays.asList(new Person("dan"), new Person("laura"));
// Method reference
people.forEach(Person::printName);
// Lambda expression
people.forEach(person -> person.printName());
// normal
for (final Person person : people) {
person.printName();
}
}
private static class Person {
private String name;
public Person(final String name) {
this.name = name;
}
public void printName() {
System.out.println(name);
}
}
}
This calls the method Person.getName for each Person object in the list. Person is the particular type, and the arbitrary object is the instance of Person that is used during each loop. This looks very similar to a reference to a static method, but the difference is how the object is passed to the method reference. Remember, a static reference passes the current object into the method, whereas an arbitrary method reference invokes a method onto the current object.
Reference to a Constructor
public class ConstructorMethodReference {
public static void main(String args[]) {
final List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Method Reference
copyElements(null, ArrayList<Integer>::new);
// Lambda expression
copyElements(list, () -> new ArrayList<Integer>());
}
private static void copyElements(final List<Integer> list, final Supplier<Collection<Integer>> targetCollection) {
// Method reference to a particular instance
list.forEach(targetCollection.get()::add);
}
}
This is the example I had the most trouble trying to make, as no matter how hard I thought, I couldn’t think of a way this could be used in something complicated. I am sure my opinion would change if I used Java 8 while at work, but for now, I do not see why this type of method reference is particularly useful. The example uses the Supplier functional interface to pass Integer::new into the copyElements method.
Conclusion
In conclusion, method references can be used to make your code even more concise, but they have some restrictions on when they can be used for and what they can do. If you simplify your code by using a lambda expression, then you might be able to make it even shorter by using a method reference. Eventually, your code will be so short your bosses will wonder what you have even been doing as you have only written a few lines of code!
Published at DZone with permission of Dan Newton, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments