Pour résumer le lien que Jon a posté 1 au cas où il tomberait en panne, "SAM" signifie "single abstract method" (méthode abstraite unique), et "SAM-type" fait référence à des interfaces telles que Runnable
, Callable
etc. Les expressions lambda, une nouvelle fonctionnalité de Java 8, sont considérées comme un type SAM et peuvent être librement converties en elles.
Par exemple, avec une interface comme celle-ci :
public interface Callable<T> {
public T call();
}
Vous pouvez déclarer un Callable
en utilisant des expressions lambda comme ceci :
Callable<String> strCallable = () -> "Hello world!";
System.out.println(strCallable.call()); // prints "Hello world!"
Dans ce contexte, les expressions lambda ne sont que du sucre syntaxique. Elles ont une meilleure apparence dans le code que les classes anonymes et sont moins restrictives sur la dénomination des méthodes. Prenez cet exemple dans le lien :
class Person {
private final String name;
private final int age;
public static int compareByAge(Person a, Person b) { ... }
public static int compareByName(Person a, Person b) { ... }
}
Person[] people = ...
Arrays.sort(people, Person::compareByAge);
Cela crée un Comparator
à l'aide d'une méthode spécifique qui ne porte pas le même nom que la méthode Comparator.compare
De cette façon, vous n'êtes pas obligé de suivre le nommage des méthodes de l'interface et vous pouvez avoir plusieurs surcharges de comparaison dans une classe, puis créer les comparateurs à la volée via les expressions lambda.
Approfondir...
À un niveau plus profond, Java les met en œuvre à l'aide de la fonction invokedynamic
instruction de bytecode ajoutée dans Java 7. J'ai dit précédemment que la déclaration d'une Lambda crée une instance de Callable
o Comparable
similaire à une classe anonyme, mais ce n'est pas strictement vrai. Au lieu de cela, la première fois que le invokedynamic
est appelé, il crée un gestionnaire de fonction Lambda en utilisant la fonction LambdaMetafactory.metafactory
méthode Il utilise ensuite cette instance en cache dans les invocations futures de la lambda. Vous trouverez plus d'informations dans cette réponse .
Cette approche est complexe et comprend même du code capable de lire des valeurs et des références primitives directement à partir de la mémoire de la pile pour les transmettre à votre code Lambda (par exemple, pour contourner la nécessité d'allouer un fichier de type Object[]
pour invoquer votre Lambda), mais elle permet aux itérations futures de l'implémentation Lambda de remplacer les anciennes implémentations sans avoir à se soucier de la compatibilité du bytecode. Si les ingénieurs d'Oracle modifient l'implémentation sous-jacente de Lambda dans une nouvelle version de la JVM, les Lambda compilés sur une ancienne JVM utiliseront automatiquement la nouvelle implémentation sans aucune modification de la part du développeur.
1 La syntaxe du lien est obsolète. Jetez un coup d'œil à la Lambda Expressions Java Trail pour voir la syntaxe actuelle.