L'opérateur Double Colon dans Java 8

1. Vue d'ensemble

Dans cet article rapide, nous discuterons de l' opérateur double-virgule ( : :) dans Java 8 et passerons en revue les scénarios dans lesquels l'opérateur peut être utilisé.

2. De Lambdas à Double Colon Operator

Avec les expressions Lambdas, nous avons vu que le code peut devenir très concis.

Par exemple, pour créer un comparateur , la syntaxe suivante suffit:

Comparator c = (Computer c1, Computer c2) -> c1.getAge().compareTo(c2.getAge()); 

Ensuite, avec l'inférence de type:

Comparator c = (c1, c2) -> c1.getAge().compareTo(c2.getAge());

Mais pouvons-nous rendre le code ci-dessus encore plus expressif et lisible? Regardons:

Comparator c = Comparator.comparing(Computer::getAge); 

Nous avons utilisé l' opérateur :: comme raccourci pour les lambdas appelant une méthode spécifique - par nom. Et au final, le résultat est bien sûr une syntaxe encore plus lisible.

3. Comment ça marche?

En termes très simples, lorsque nous utilisons une référence de méthode - la référence cible est placée avant le délimiteur :: et le nom de la méthode est fourni après.

Par exemple:

Computer::getAge;

Nous examinons une référence de méthode à la méthode getAge définie dans la classe Computer .

On peut alors opérer avec cette fonction:

Function getAge = Computer::getAge; Integer computerAge = getAge.apply(c1); 

Notez que nous référençons la fonction - puis l'appliquons au bon type d'argument.

4. Références de méthode

Nous pouvons faire bon usage de cet opérateur dans de nombreux scénarios.

4.1. Une méthode statique

Tout d'abord, nous allons utiliser une méthode utilitaire statique :

List inventory = Arrays.asList( new Computer( 2015, "white", 35), new Computer(2009, "black", 65)); inventory.forEach(ComputerUtils::repair); 

4.2. Une méthode d'instance d'un objet existant

Ensuite, examinons un scénario intéressant - référençant une méthode d'une instance d'objet existante .

Nous allons utiliser la variable System . out - un objet de type PrintStream qui prend en charge la méthode d' impression :

Computer c1 = new Computer(2015, "white"); Computer c2 = new Computer(2009, "black"); Computer c3 = new Computer(2014, "black"); Arrays.asList(c1, c2, c3).forEach(System.out::print); 

4.3. Une méthode d'instance d'un objet arbitraire d'un type particulier

Computer c1 = new Computer(2015, "white", 100); Computer c2 = new MacbookPro(2009, "black", 100); List inventory = Arrays.asList(c1, c2); inventory.forEach(Computer::turnOnPc); 

Comme vous pouvez le voir, nous référençons la méthode turnOnPc non pas sur une instance spécifique, mais sur le type lui-même.

À la ligne 4, la méthode d'instance turnOnPc sera appelée pour chaque objet de l' inventaire .

Et cela signifie naturellement que - pour c1, la méthode turnOnPc sera appelée sur l' instance Computer et pour c2 sur l' instance MacbookPro .

4.4. Une super méthode d'un objet particulier

Supposons que vous ayez la méthode suivante dans la superclasse Computer :

public Double calculateValue(Double initialValue) { return initialValue/1.50; } 

et celui-ci dans la sous-classe MacbookPro :

@Override public Double calculateValue(Double initialValue){ Function function = super::calculateValue; Double pcValue = function.apply(initialValue); return pcValue + (initialValue/10) ; } 

Un appel à la méthode CalculateValue sur une instance MacbookPro :

macbookPro.calculateValue(999.99); 

produira également un appel à CalculateValue sur la superclasse Computer .

5. Références du constructeur

5.1. Créer une nouvelle instance

Référencer un constructeur pour instancier un objet peut être assez simple:

@FunctionalInterface public interface InterfaceComputer { Computer create(); } InterfaceComputer c = Computer::new; Computer computer = c.create(); 

Et si vous avez deux paramètres dans un constructeur?

BiFunction c4Function = Computer::new; Computer c4 = c4Function.apply(2013, "white"); 

Si les paramètres sont au moins trois, vous devez définir une nouvelle interface fonctionnelle:

@FunctionalInterface interface TriFunction { R apply(A a, B b, C c); default  TriFunction andThen( Function after) { Objects.requireNonNull(after); return (A a, B b, C c) -> after.apply(apply(a, b, c)); } } 

Ensuite, initialisez votre objet:

TriFunction  c6Function = Computer::new; Computer c3 = c6Function.apply(2008, "black", 90); 

5.2. Créer un tableau

Enfin, voyons comment créer un tableau d' objets Computer avec cinq éléments:

Function  computerCreator = Computer[]::new; Computer[] computerArray = computerCreator.apply(5); 

6. Conclusion

Comme nous commençons à le voir, l'opérateur double-virgule - introduit dans Java 8 - sera très utile dans certains scénarios, et en particulier en conjonction avec Streams.

Il est également très important de jeter un œil aux interfaces fonctionnelles pour mieux comprendre ce qui se passe dans les coulisses.

Le code source complet de l'exemple est disponible dans ce projet GitHub - il s'agit d'un projet Maven et Eclipse afin qu'il puisse être importé et utilisé tel quel.