::
est appelé référence de méthode. Il s'agit essentiellement d'une référence à une seule méthode. C'est-à-dire qu'il fait référence à une méthode existante par son nom.
Brève explication :
Voici un exemple de référence à une méthode statique:
class Hey {
public static double square(double num){
return Math.pow(num, 2);
}
}
Function<Double, Double> square = Hey::square;
double ans = square.apply(23d);
square
peut être transmis comme des références d'objet et déclenché en cas de besoin. En fait, il peut tout aussi bien être utilisé comme référence à des méthodes "normales" d'objets que static
celles. Par exemple:
class Hey {
public double square(double num) {
return Math.pow(num, 2);
}
}
Hey hey = new Hey();
Function<Double, Double> square = hey::square;
double ans = square.apply(23d);
Function
ci-dessus est une interface fonctionnelle . Pour bien comprendre ::
, il est également important de comprendre les interfaces fonctionnelles. En clair, une interface fonctionnelle est une interface avec une seule méthode abstraite.
Des exemples d'interfaces fonctionnelles comprennent Runnable
, Callable
et ActionListener
.
Function
ci - dessus est une interface fonctionnelle avec une seule méthode: apply
. Il prend un argument et produit un résultat.
La raison pour laquelle les ::
s sont géniaux est que :
Les références de méthode sont des expressions qui ont le même traitement que les expressions lambda (...), mais au lieu de fournir un corps de méthode, elles font référence à une méthode existante par son nom.
Par exemple, au lieu d'écrire le corps lambda
Function<Double, Double> square = (Double x) -> x * x;
Vous pouvez simplement faire
Function<Double, Double> square = Hey::square;
Au moment de l'exécution, ces deux square
méthodes se comportent exactement de la même manière l'une que l'autre. Le bytecode peut être ou ne pas être le même (bien que, dans le cas ci-dessus, le même bytecode soit généré; compilez ce qui précède et vérifiez avec javap -c
).
Le seul critère majeur à satisfaire est: la méthode que vous fournissez doit avoir une signature similaire à la méthode de l'interface fonctionnelle que vous utilisez comme référence d'objet .
Ce qui suit est illégal:
Supplier<Boolean> p = Hey::square; // illegal
square
attend un argument et retourne a double
. La get
méthode de Supplier renvoie une valeur mais ne prend pas d'argument. Par conséquent, cela entraîne une erreur.
Une référence de méthode fait référence à la méthode d'une interface fonctionnelle. (Comme mentionné, les interfaces fonctionnelles ne peuvent avoir qu'une seule méthode chacune).
Quelques exemples supplémentaires: la accept
méthode dans Consumer prend une entrée mais ne renvoie rien.
Consumer<Integer> b1 = System::exit; // void exit(int status)
Consumer<String[]> b2 = Arrays::sort; // void sort(Object[] a)
Consumer<String> b3 = MyProgram::main; // void main(String... args)
class Hey {
public double getRandom() {
return Math.random();
}
}
Callable<Double> call = hey::getRandom;
Supplier<Double> call2 = hey::getRandom;
DoubleSupplier sup = hey::getRandom;
// Supplier is functional interface that takes no argument and gives a result
Ci-dessus, getRandom
ne prend aucun argument et renvoie a double
. Ainsi, toute interface fonctionnelle qui satisfait aux critères de: prendre aucun argument et retournerdouble
peut être utilisée.
Un autre exemple:
Set<String> set = new HashSet<>();
set.addAll(Arrays.asList("leo","bale","hanks"));
Predicate<String> pred = set::contains;
boolean exists = pred.test("leo");
En cas de types paramétrés :
class Param<T> {
T elem;
public T get() {
return elem;
}
public void set(T elem) {
this.elem = elem;
}
public static <E> E returnSame(E elem) {
return elem;
}
}
Supplier<Param<Integer>> obj = Param<Integer>::new;
Param<Integer> param = obj.get();
Consumer<Integer> c = param::set;
Supplier<Integer> s = param::get;
Function<String, String> func = Param::<String>returnSame;
Les références de méthode peuvent avoir différents styles, mais fondamentalement, elles signifient toutes la même chose et peuvent simplement être visualisées comme des lambdas:
- Une méthode statique (
ClassName::methName
)
- Une méthode d'instance d'un objet particulier (
instanceRef::methName
)
- Une super méthode d'un objet particulier (
super::methName
)
- Une méthode d'instance d'un objet arbitraire d'un type particulier (
ClassName::methName
)
- Une référence de constructeur de classe (
ClassName::new
)
- Une référence de constructeur de tableau (
TypeName[]::new
)
Pour plus d'informations, voir http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html .