usar tutorial funciones expresiones explicacion example español ejercicios ejemplos como anonimas lambda java-8 javac

tutorial - ¿Por qué las lambdas en Java 8 no permiten la referencia a las variables miembro donde las clases anónimas no lo hacen?



java 8 lambda explicacion (1)

El error # JDK-8027941 describe exactamente esto. Dan Smith (Project Lambda Specification Lead) escribe que no es un error, y no se limita a las lambdas.

En los comentarios sobre un informe de error relacionado , lo pone así:

8.3.2.3: Primero, un "uso" de un campo en un inicializador de campo generalmente está prohibido si el uso ocurre antes de la declaración del campo. La especificación no es muy clara en esto, pero la intención siempre ha sido que "antes" incluya el inicializador propio del campo. Entonces " int x = x+1; " no es una declaración de campo válida.

También remarca:

Se podría agregar una característica que trataría los cuerpos lambda especialmente, como los cuerpos de clases anónimas (o, más generalmente, permitir que un lambda se refiera a sí mismo si es un inicializador variable), pero esto no se ha hecho. (FWIW, una modificación simple de 8.3.2.3 no sería completamente segura, al igual que la cuarta viñeta no es completamente segura en este momento: " Function f = (Function) ((Function) e -> f.apply(e)).apply(null); ".)

Creo que el problema es que los diseñadores de Java quieren tener reglas sintácticas simples para decidir qué tipo de declaraciones se permiten, en lugar de depender de un análisis de código semántico más complejo. El beneficio es probablemente una especificación más simple y, por lo tanto, menos requisitos para los compiladores, mientras que el costo es que los programadores no pueden expresar todos los programas, al menos no de la manera que quieren.

Como señala Marko Topolnik, hay una solución: calificar completamente el campo. Ejemplo del informe de error:

import java.util.function.Function; public class LambdaSelfRef { // COMPILATION FAILURE public static Function<Object, Object> op1 = e -> op1.apply(e); // COMPILES OK public static Function<Object, Object> op2 = e -> LambdaSelfRef.op2.apply(e); /* ... */ }

La siguiente clase contiene una variable miembro runnable que se inicializa con una instancia de una clase interna anónima. La clase interna hace referencia al mismo miembro:

class Example { Runnable runnable = new Runnable() { @Override public void run() { System.out.println(runnable); } }; }

Esto no es un problema siempre que el método no se ejecute antes de que el miembro haya sido asignado y el JLS permita dicha referencia.

La declaración de la variable miembro se podría convertir teóricamente a una expresión lambda como esta:

Runnable runnable = () -> System.out.println(runnable);

A mi entender, esto es funcionalmente equivalente al ejemplo anterior, pero javac 1.8.0_05 con el siguiente mensaje de error:

Error:(2, 54) java: self-reference in initializer

Si bien esa afirmación es cierta, no veo por qué se rechazó esto. ¿Esto fue intencionalmente rechazado, tal vez porque las expresiones lambda se compilan a un código de bytes diferente que podría causar problemas si se permitiera? ¿O simplemente se rechazó porque ya existían problemas con estas referencias cuando se usaban en clases internas anónimas? ¿O fue rechazado involuntariamente por los escritores de JLS? ¿O es un error en javac ?