Pourquoi cette version de Java 8 ne parvient-elle pas à se comstackr?

Le code Java suivant ne parvient pas à comstackr:

@FunctionalInterface private interface BiConsumer { void accept(A a, B b); } private static void takeBiConsumer(BiConsumer bc) { } public static void main(Ssortingng[] args) { takeBiConsumer((Ssortingng s1, Ssortingng s2) -> new Ssortingng("hi")); // OK takeBiConsumer((Ssortingng s1, Ssortingng s2) -> "hi"); // Error } 

Le compilateur rapporte:

 Error:(31, 58) java: incompatible types: bad return type in lambda expression java.lang.Ssortingng cannot be converted to void 

La chose étrange est que la ligne marquée “OK” comstack bien, mais la ligne marquée “Erreur” échoue. Ils semblent essentiellement identiques.

    Votre lambda doit être conforme à BiConsumer . Si vous vous référez à JLS # 15.27.3 (Type d’un Lambda) :

    Une expression lambda est conforme à un type de fonction si toutes les conditions suivantes sont remplies:

    • […]
    • Si le résultat du type de fonction est nul, le corps lambda est soit une expression d’instruction (§14.8), soit un bloc compatible avec les vides.

    Donc, le lambda doit être soit une expression d’instruction, soit un bloc compatible avec les valeurs vides:

    • Une invocation de constructeur est une expression de déclaration qui comstack.
    • Un littéral de chaîne n’est pas une expression d’instruction et n’est pas compatible avec les vides (voir les exemples du 15.27.2 ), il ne comstack donc pas.

    De manière simple, new Ssortingng("hi") est un morceau de code exécutable qui fait réellement quelque chose (il crée une nouvelle chaîne puis la retourne). La valeur renvoyée peut être ignorée et new Ssortingng("hi") peut toujours être utilisé dans void-return lambda pour créer une nouvelle chaîne.

    Cependant, "hi" est juste une constante qui ne fait rien sur elle-même. La seule chose raisonnable à faire avec elle dans lambda body est de la renvoyer . Mais la méthode lambda devrait avoir un type de retour Ssortingng ou Object , mais elle retourne void , donc la Ssortingng cannot be casted to void erreur.

    Le premier cas est correct car vous appelez une méthode “spéciale” (un constructeur) et vous ne prenez pas réellement l’object créé. Juste pour que ce soit plus clair, je vais mettre les accolades optionnelles dans vos lambdas:

     takeBiConsumer((Ssortingng s1, Ssortingng s2) -> {new Ssortingng("hi");}); // OK takeBiConsumer((Ssortingng s1, Ssortingng s2) -> {"hi"}); // Error 

    Et plus clairement, je vais traduire cela par l’ancienne notation:

     takeBiConsumer(new BiConsumer(Ssortingng s1, Ssortingng s2) { public void accept(Ssortingng s, Ssortingng s2) { new Ssortingng("hi"); // OK } }); takeBiConsumer(new BiConsumer(Ssortingng s1, Ssortingng s2) { public void accept(Ssortingng s, Ssortingng s2) { "hi"; // Here, the comstackr will attempt to add a "return" // keyword before the "hi", but then it will fail // with "comstackr error ... bla bla ... // java.lang.Ssortingng cannot be converted to void" } }); 

    Dans le premier cas, vous exécutez un constructeur, mais vous ne retournez PAS l’object créé. Dans le second cas, vous tentez de renvoyer une valeur Ssortingng, mais votre méthode dans votre interface BiConsumer renvoie une erreur, d’où l’erreur de compilation.

    Les JLS précisent que

    Si le résultat du type de fonction est nul, le corps lambda est soit une expression d’instruction (§14.8), soit un bloc compatible avec les vides.

    Maintenant, voyons cela en détail,

    Comme votre méthode takeBiConsumer est de type void, lambda recevant la new Ssortingng("hi") l’interprétera comme un bloc comme

     { new Ssortingng("hi"); } 

    qui est valide dans un vide, d’où le premier cas compilé.

    Cependant, dans le cas où le lambda est -> "hi" , un bloc tel que

     { "hi"; } 

    n’est pas une syntaxe valide en Java. Par conséquent, la seule chose à faire avec “salut” est d’essayer de le retourner.

     { return "hi"; } 

    qui n’est pas valide dans un vide et explique le message d’erreur

     incompatible types: bad return type in lambda expression java.lang.Ssortingng cannot be converted to void 

    Pour une meilleure compréhension, notez que si vous changez le type de takeBiConsumer en une chaîne, -> "hi" sera valide car il essaiera simplement de retourner directement la chaîne.


    Notez qu’au début, je pensais que l’erreur était due au fait que le lambda était dans un contexte d’invocation incorrect, alors je partagerai cette possibilité avec la communauté:

    JLS 15.27

    C’est une erreur de compilation si une expression lambda se produit dans un programme autre que le contexte d’affectation (§5.2), un contexte d’invocation (§5.3) ou un contexte de casting (§5.5).

    Cependant, dans notre cas, nous sums dans un contexte d’invocation correct.