Method References

Goals

Concepts

Language

Library

Preview

final List<Point> points = getPoints();
points.sort(comparing(point::getX));

Lesson

In the previous lesson you learned how lambda expressions can facilitate implementing single-method functional interfaces. You looked at an example of Scene for holding points, initialized with a Plotter<Point> strategy for placing the points on some two-dimensional plane. A lambda expression allows implementation of Plotter<Point> without all the boilerplate usually associated with anonymous classes.
A scene with a Plotter<T> strategy plotting objects on a plane.
public class Scene {

  private final Plotter<Point> plotter;

  private final Set<Point> points; //TODO implement methods for adding points

  /** Plotter strategy constructor.
   * @param plotter The strategy for plotting points.
   */
  public Scene(@Nonnll final Plotter<Point> plotter) {
    this.plotter = checkNotNull(plotter);
  }

  /** Plots all the points on the plane. */
  public void plot() {
    for(final Point point : points) {
      plotter.plot(point);  //plot the point using the strategy
    }
  }

}
@FunctionalInterface
public interface Plotter<T> {

  void plot(T object);

}
final Scene scene = new Scene(point -> System.out.println(point));
scene.plot();

Method References

If you do nothing more in the body of your lambda expression than call a single method with the same parameters as the lambda, as in the example above, Java provides an even shorter representation called a method reference. Although Java does not really allow a true reference to a method, the method reference syntax will produce the equivalent of a lambda that calls the method you indicate. A method reference consists of the object or class on which the method will be invoked, followed by two colon :: characters, followed by the name of the method.

Instance Method References

Remembering from above that a Scene constructor takes a functional interface with a single method Plotter.plot(Point), the lambda expression above is equivalent to the method reference System.out::println, referring to the println() method of the System.out instance:

A lambda expression calling a static method, and an equivalent method reference.
final Scene scene1 = new Scene(point -> System.out.println(point));  //lambda expression
final Scene scene2 = new Scene(System.out::println);  //equivalent method reference

You can refer to the appropriate instance method of any object you have a reference too. If it is not evident from the above example that System.out::println is an instance method reference, imagine that a class Voice has a method Voice.say(Point). If you have a reference to a Voice you could pass it to the scene as a way to plot each point.

A method reference to an instance method.
final Voice voice = new Voice();  //Voice has a Voice.say(Point) method
final Scene scene3 = new Scene(voice::say);  //"plot" each point by saying it

Static Method References

Method references to static methods are just as straightforward; simply use the name of the class that has the static method instead of the instance variable that has the instance method.

Let's say that you have a general ConsolePresentation class of static utilities for outputting things to the console. You could pass a static reference to ConsolePresentation::printPoint to the Scene constructor as an implementation of Plotter<Point>

Console presentation static utilities.
public class ConsolePresentation {

  public static void printPoint(final Point point) {
    System.out.println(String.format("(%s, %s)", point.getX(), point.getY()));
  }

}
final Scene scene4 = new Scene(point -> ConsolePresentation.printPoint(point));  //lambda expression
final Scene scene5 = new Scene(ConsolePresentation::printPoint);  //equivalent method reference

Type Method References

You can also refer to an instance method of one of the functional interface parameters by using class representing the object's type.

Maybe the Scene that we've been using has a method to print all the points it knows about. The Scene.printAllPoints(PointLabelGenerator) method takes a strategy for generating a label for points:

A strategy for generating a label string for each Point.
@FunctionalInterface
public interface PointLabelGenerator {

  String generateLabel(@Nonnull Point point);

}

We could then ask a scene to print out all the points using an anonymous class to implement PointLabelGenerator.

Printing points with an anonymous implementation of PointLabelGenerator.
scene.printAllPoints(new PointLabelGenerator() {
  @Override
  public String generateLabel(@Nonnull final Point point) {
    return point.toString();
  }
});

With lambdas that becomes much more readable:

Printing points with a lambda expression for PointLabelGenerator.
scene.printAllPoints(point -> point.toString());

But because the lambda simply invokes a method on the in the parameter, we can simply pass a method reference and make things even clearer:

Printing points with a method reference for PointLabelGenerator.
scene.printAllPoints(Point::toString);

A method reference to an instance method of the parameter object can have another twist: it can call a method on one parameter and use the other parameter(s) as arguments to the method call! Imagine that the scene point printing method actually has two parameters, with the second being a strategy for grouping points in the output: Scene.printAllPoints(PointLabelGenerator, PointGrouper). The PointGrouper strategy is a functional interface for indicating whether two points should be grouped together:

A strategy for grouping Point instances together.
@FunctionalInterface
public interface PointGrouper {

  boolean isGroup(@Nonnull Point point1, @Nonnull Point point2);

}

Furthermore let's say that the Point class has a method for determining if a point is in the same quadrant as another point. (That is, each of the X and Y coordinates has the same sign as that of the other point.)

A method to determine if one point is in the same quadrant as the other.
public class Point {

  …

  /** Determines if two points are in the same quadrant.
   * <p>Note that this implementation considers coordinates of zero
   * to fall on  the positive side of the axis.</p>
   * @param point THe point to compare with this point.
   */
  public boolean isSameQuadrant(@Nonnull final Point point) {
    return ((getX() >= 0) == (point.getX() >= 0))
        && ((getY() >= 0) == (point.getY() >= 0));
  }

}
Using an anonymous classes we could call the new Scene.printAllPoints(PointLabelGenerator, PointGrouper) method like this:
Grouping points with an anonymous implementation of PointLabelGenerator.
scene.printAllPoints(Point::toString, new PointGrouper() {
  @Override
  public boolean isGroup(@Nonnull final Point point1, @Nonnull final Point point2) {
    return point1.isSameQuadrant(point2);
  }
});

With a lambda expression, of course, that becomes much more compact:

Grouping points with a lambda expression for PointLabelGenerator.
scene.printAllPoints(Point.toString, (point1, point2) -> point1.isSameQuadrant(point2));

Again this lambda is only a method call—but notice that the method call is invoked on the first lambda parameter, passing in the second lambda parameter as an argument. We can still replace this with a method reference!

Grouping points with a method reference for PointLabelGenerator.
scene.printAllPoints(Point::toString, Point::isSameQuadrant);

Constructor References

You can even reference a constructor using the syntax ::new. If a method calls for a functional interface that produces a Foo, you can pass in the constructor reference Foo::new, if its parameters match the given parameters (or a default constructor if no other parameters are given). This even works with arrays, such as int[]::new.

Method References in Functions

When exploring lambda expressions, you learned that Java provides a number of useful functional interfaces in the java.util.function package. One of them, java.util.function.Predicate<T>, defines a strategy for testing an object in some way and returning a boolean result. You discovered how to remove items matching a Predicate<T> from a collection by calling the Collection.removeIf(Predicate<? super E> filter) and passing a lambda:
Removing elements from a collection using Collection.removeIf(…).
final List<String> strings = …;
//remove all strings that start with "foo" from the list
strings.removeIf(strings, string -> string.startsWith("foo"));

Remember that if you have an existing method that matches the arguments of the functional interface method, you could use a method reference instead of a lambda. What if you wanted to remove all empty strings from a list? You could use the same Collection.removeIf(Predicate<? super E> filter) method, calling the String.isEmpty() method in the lambda expression representing the Predicate<T>:

Removing empty strings from a list using a lambda expression as a Predicate<T>.
final List<String> strings = …;
//remove all empty strings from the list
strings.removeIf(strings, string -> string.Empty());

Because String.isEmpty() does not have any extra parameters (unlike String.startsWith(String)), you could use a method reference to String::isEmpty to make your code even more concise. The String part of String::isEmpty would refer to the functional interface String parameter, as is evident in the lambda expression above..

Removing empty strings from a list using a method reference as a Predicate<T>.
final List<String> strings = …;
//remove all empty strings from the list
strings.removeIf(strings, String::isEmpty);

Higher-Order Functions

You can just as easily use method references for passing functions to higher-order function methods. In a previous lesson you used the static method Comparator<T> Comparator.comparing(Function<? super T,? extends U> keyExtractor) to produce a Comparator<T>. When calling List.sort(Comparator<? super E> comparator) you passed in a Function<T, R> that determines the comparison value for an object, using a lambda expression to implement the Function<T, R> interface:

Using Comparator.comparing(…) to produce a Comparator<T> for comparing Point instances.
final List<Point> points = …;
points.sort(Comparator.comparing(point -> point.getX()));

We can do even better than that using a method reference to Point.getX(). For added simplicity we can statically import Comparator.comparing(…) so that the entire statement flows like a sentence.

Using Comparator.comparing(…) with a method reference for comparing Point instances.
final List<Point> points = …;
points.sort(comparing(Point::getX));

Internal Iteration

Internal iteration via the Iterable.forEach(Consumer<? super T> action) can also be made more concise with method references. In a previous lesson you learned how to used a lambda expression to simplify the implementation of java.util.function.Consumer<T> when calling Iterable.forEach(…).

Iterating over a list using internal iteration.
final List<String> numbers = Arrays.asList("one", "two", "three");
numbers.forEach(number -> System.out.println(number));

Because the lambda in the above example simply delegates to the method System.out.println(…) with a single argument, the entire expression can be replaced with a method reference to System.out::println.

Iterating over a list using internal iteration with a method reference.
final List<String> numbers = Arrays.asList("one", "two", "three");
numbers.forEach(System.out::println);

Review

Summary

Common forms of method references:

Form Example Description
object::method fooBar::doSomething Reference to an instance method of an object. Can also be used with this:: or super::.
Class::method Utilities::doSomething Reference to a static method of a class.
Type::method FooBar::doSomething Reference to a method of one of the functional interface parameters.
Class::new FooBar::new Reference to a class constructor.

Think About It

Task

You have already created a Booker.listPublications(…) method for display of publications in the presentation layer. So far this method has been specific to the command-line interface. You decide that you you want to make the division between the presentation concern and the business concern more evident by extracting the logic for printing publication to stdout into a separate method from the general publication listing method.

Use method references in your comparator strategies wherever possible.

See Also