À quoi sert une expression Java 8 Lambda? [dupliquer]


Cette question a déjà une réponse ici:

Considérez l'extrait de code Java 8 suivant.

public static void main(String[] args) {            
   List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);

   Consumer<Integer>  consumer = x -> System.out.print(x);  

   integers.forEach(consumer);
}

Dans quoi Consumer<Integer> consumer = x -> System.out.print(x) est-il compilé?

Je comprends que les Lambdas ne sont pas implémentés en tant que classes internes anonymes. Cependant Consumer<Integer> est une interface donc x -> System.out.print(x) doit être produire un objet quelconque, mais on ne sait pas quel type d'objet est produit.

Est-il un nouveau type d'objet dans Java 8 pour représenter une expression lambda?

Update Voici le programme décompilé le programme a été respecté avec le complier eclipse java 8 et la sortie ci-dessous provient d'eclipse lorsque vous ouvrez un fichier de classe.

Il semble que l'expression lambda se transforme en une méthode statique sur la classe qui contient le lambda expression private static synthetic void lambda$0(java.lang.Integer x);

// Compiled from Example.java (version 1.8 : 52.0, super bit)
public class Example {

  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public Example();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [8]
    4  return
      Line numbers:
        [pc: 0, line: 7]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: Example

  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 4, Locals: 3
  public static void main(java.lang.String[] args);
     0  iconst_5
     1  anewarray java.lang.Integer [16]
     4  dup
     5  iconst_0
     6  iconst_1
     7  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    10  aastore
    11  dup
    12  iconst_1
    13  iconst_2
    14  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    17  aastore
    18  dup
    19  iconst_2
    20  iconst_3
    21  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    24  aastore
    25  dup
    26  iconst_3
    27  iconst_4
    28  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    31  aastore
    32  dup
    33  iconst_4
    34  iconst_5
    35  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    38  aastore
    39  invokestatic java.util.Arrays.asList(java.lang.Object[]) : java.util.List [22]
    42  astore_1 [integers]
    43  invokedynamic 0 accept() : java.util.function.Consumer [31]
    48  astore_2 [consumer]
    49  getstatic java.lang.System.out : java.io.PrintStream [32]
    52  aload_2 [consumer]
    53  invokevirtual java.lang.Object.getClass() : java.lang.Class [38]
    56  invokevirtual java.lang.Class.getCanonicalName() : java.lang.String [42]
    59  invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]
    62  getstatic java.lang.System.out : java.io.PrintStream [32]
    65  aload_2 [consumer]
    66  invokevirtual java.lang.Object.getClass() : java.lang.Class [38]
    69  invokevirtual java.lang.Class.getTypeName() : java.lang.String [54]
    72  invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]
    75  aload_1 [integers]
    76  aload_2 [consumer]
    77  invokeinterface java.util.List.forEach(java.util.function.Consumer) : void [57] [nargs: 2]
    82  return
      Line numbers:
        [pc: 0, line: 10]
        [pc: 43, line: 12]
        [pc: 49, line: 14]
        [pc: 62, line: 15]
        [pc: 75, line: 17]
        [pc: 82, line: 18]
      Local variable table:
        [pc: 0, pc: 83] local: args index: 0 type: java.lang.String[]
        [pc: 43, pc: 83] local: integers index: 1 type: java.util.List
        [pc: 49, pc: 83] local: consumer index: 2 type: java.util.function.Consumer
      Local variable type table:
        [pc: 43, pc: 83] local: integers index: 1 type: java.util.List<java.lang.Integer>
        [pc: 49, pc: 83] local: consumer index: 2 type: java.util.function.Consumer<java.lang.Integer>

  // Method descriptor #73 (Ljava/lang/Integer;)V
  // Stack: 2, Locals: 1
  private static synthetic void lambda$0(java.lang.Integer x);
    0  getstatic java.lang.System.out : java.io.PrintStream [32]
    3  aload_0 [x]
    4  invokevirtual java.io.PrintStream.print(java.lang.Object) : void [74]
    7  return
      Line numbers:
        [pc: 0, line: 12]
      Local variable table:
        [pc: 0, pc: 8] local: x index: 0 type: java.lang.Integer

  Inner classes:
    [inner class info: #96 java/lang/invoke/MethodHandles$Lookup, outer class info: #98 java/lang/invoke/MethodHandles
     inner name: #100 Lookup, accessflags: 25 public static final]
Bootstrap methods:
  0 : # 89 arguments: {#90,#93,#94}
}
Author: ams, 2014-02-18

1 answers

Le projet actuel de la spécification du langage Java 8 indique (chapitre 15.27.4)

La valeur d'une expression lambda est une référence à une instance d'un classe avec les propriétés suivantes:

  • La classe implémente l'interface fonctionnelle ciblée et, si le type cible est un type d'intersection, tous les autres éléments d'interface de l'intersection.
  • La classe déclare une méthode qui remplace l'interface fonctionnelle supertype méthodes abstraites (et, potentiellement, d'autres méthodes de son superinterfaces).
  • Les types de paramètres de la méthode, le type de retour et les types jetés sont donnés par le type de fonction de l'interface.
  • Le corps de la méthode a pour effet d'évaluer le corps lambda, s'il s'agit d'une expression, ou d'exécuter le corps lambda, s'il s'agit d'un bloc; si un résultat est attendu, il est renvoyé par la méthode.
  • La classe ne remplace aucune autre méthode de l'interface ou des interfaces mentionné ci - dessus, sauf qu'il peut remplacer les méthodes du Object classe.

Notez que le JLS ne dit rien sur la façon dont le code doit être compilé, sauf que le code octet doit prendre en charge la spécification ci-dessus.

En tant que tel, l'objet renvoyé par l'expression lambda

x -> System.out.print(x);  

Sera une instance d'une classe qui suit les règles ci-dessus.

, compte tenu de votre commentaire que

consumer.getClass()

Renvoie la classe suivante

Example$$Lambda$1/1072591677

Il il semble qu'il génère une classe de type proxy spécifique aux expressions lambda.

Voir ici:

 8
Author: Sotirios Delimanolis, 2017-05-23 11:53:13