Method references provide easy-to-read lambda expressions for methods that already have a name.
The method reference Car
(c1,c2)->Car.compareByEngineCC(c1,c2).
Each has the following characteristics:
The method reference myComparisonProvider::compareByEngineCC invokes the method compareByEngineCC that is part of the object myComparisonProvider. The JRE infers the method type arguments, which in this case are (Car, Car).
String[] stringArray = { "Alice", "Bob", "Erin", "Dave ", , "Robert", "Michael", "Linda" }; Arrays.sort(stringArray, String::compareToIgnoreCase);
public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>>
DEST transferElements(SOURCE sourceCollection,
Supplier<DEST> collectionFactory) {
DEST result = collectionFactory.get();
for (T t : sourceCollection) {
result.add(t);
}
return result;
}
You can use a constructor reference in place of the lambda expression as follows:
Set<Car> transformedSet = transferElements(roster, HashSet::new);
The Java compiler infers that you want to create a
Set<Car> transformedSet = transferElements(roster, HashSet<Car>::new);
More new features of the java 8 will be discussed in my next posts. Thank you for reading this post, please post you suggestions and comments on this.
We have seen lambda expressions to crate anonymous methods in my post What's New in Java 8 - Lambda Expressions. Sometimes a lambda expression does nothing but call an existing method (will see example in detail). In those cases, we use method references instead lambda expressions. Method references are compact and easy to read lambda expressions for methods that already have a name.
Example :
To better understand, consider the same car example discussed in my previous post, but here a extra compareByEngineCC static method.
public class Car{
public enum Color {
BLACK, WHITE, RED
}
public String modelName;
public Color color;
public int engineCC;
public void printModelName() {
// ...
}
public static int compareByEngineCC(Car c1, Car c2) {
if( c1.engineCC == c2.engineCC) return 0;
return c1.engineCC > c2.engineCC?1:-1;
}
}
The requirement is sort the array of cars by engineCC, so that I added a static method to compare the cars.
We can use sort method which is static in Arrays class to meat this requirement, but in order to use this static method we need to provide Comparator, So we implemented a CarEngineCCComparator class as shown below
public class CarEngineCCComparator implements Comparator<Car> {
@Override
public int compare(Car c1, Car c2) {
return Car.compareByEngineCC(c1, c2);
}
}
and assume that array of cars is Car[] cars to be sorted.then by calling static method of Arrays class will get the sorted array
Arrays.sort(cars,new CarEngineCCComparator() );
If you observer closely, the interface Comparator is functional interface(a interface with only one abstract method), that means we can use lambda expression instead implement a new class. then our method call will be
Arrays.sort(cars,(c1,c2)->Car.compareByEngineCC(c1,c2));
Here a lambda expression does nothing but call an existing method, so in this case we use method references instead lambda expression as follows.
Arrays.sort(cars, Car::compareByEngineCC);
::
compareByEngineCC is semantically the same as the lambda expression(c1,c2)->Car.compareByEngineCC(c1,c2).
Each has the following characteristics:
- Its formal parameter list is copied from Comparator<Car>.compare, which is (Car, Car).
- Its body calls the method Car.compareByEngineCC.
Kinds of Method References:
There are four kinds of method references:
class ComparisonProvider{
Kind | Example |
---|---|
Reference to a static method | ContainingClass::staticMethodName |
Reference to an instance method of a particular object | ContainingObject::instanceMethodName |
Reference to an instance method of an arbitrary object of a particular type | ContainingType::methodName |
Reference to a constructor | ClassName::new |
Reference to a Static Method
The method reference Car::compareByEngineCC is a reference to a static method.Reference to an Instance Method of a Particular Object
The following is an example of a reference to an instance method of a particular object:class ComparisonProvider{
public int compareByEngineCC(Car c1, Car c2) {
if( c1.engineCC == c2.engineCC) return 0;
return c1.engineCC > c2.engineCC?1:-1;
}
}
ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(cars,myComparisonProvider::compareByEngineCC);
The method reference myComparisonProvider::compareByEngineCC invokes the method compareByEngineCC that is part of the object myComparisonProvider. The JRE infers the method type arguments, which in this case are (Car, Car).
Reference to an Instance Method of an Arbitrary Object of a Particular Type
The following is an example of a reference to an instance method of an arbitrary object of a particular type:String[] stringArray = { "Alice", "Bob", "Erin", "Dave ", , "Robert", "Michael", "Linda" }; Arrays.sort(stringArray, String::compareToIgnoreCase);
The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b), where a and b are arbitrary names used to better describe this example. The method reference would invoke the method a.compareToIgnoreCase(b).
Reference to a Constructor
We can reference a constructor in the same way as a static method by using the namenew
. The following method copies elements from one collection to another:public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>>
DEST transferElements(SOURCE sourceCollection,
Supplier<DEST> collectionFactory) {
DEST result = collectionFactory.get();
for (T t : sourceCollection) {
result.add(t);
}
return result;
}
The functional interface Supplier contains one method get that takes no arguments and returns an object. Consequently, you can invoke the method transferElements with a lambda expression as follows:
Set<Car> transformedSetLambda = transferElements(cars, () -> { return new HashSet<>(); });
Set<Car> transformedSetLambda = transferElements(cars, () -> { return new HashSet<>(); });
You can use a constructor reference in place of the lambda expression as follows:
Set<Car> transformedSet = transferElements(roster, HashSet::new);
The Java compiler infers that you want to create a
HashSet
collection that contains elements of type Car
. Alternatively, you can specify this as follows:Set<Car> transformedSet = transferElements(roster, HashSet<Car>::new);
No comments:
Post a Comment