Lambda esta referencia en java

Quiero convertir una anonymous class a una lambda expression . Pero esta clase anónima uso la palabra clave this .

Por ejemplo, escribí este patrón Observer/Observable simple:

 import java.util.ArrayList; import java.util.Collection; public static class Observable { private final Collection notifiables = new ArrayList(); public Observable() { } public void addObserver(Observer notifiable) { notifiables.add(notifiable); } public void removeObserver(Observer notifiable) { notifiables.add(notifiable); } public void change() { notifiables.forEach(notifiable -> notifiable.changed(this)); } } public interface Observer { void changed(Observable notifier); } 

y este código de muestra con una clase anónima (use la palabra clave this):

 public class Main { public static void main(String[] args) { Observable observable = new Observable(); observable.addObserver(new Observer() { @Override public void changed(Observable notifier) { notifier.removeObserver(this); } }); observable.change(); } } 

pero cuando lo convierto en una expresión lambda:

 public class Main { public static void main(String[] args) { Observable observable = new Observable(); observable.addObserver(notifier -> { notifier.removeObserver(this); }); observable.change(); } } 

me sale este error de comstackción:

 Cannot use this in a static context and in a non `static` context public class Main { public void main(String[] args) { method(); } private void method() { Observable observable = new Observable(); observable.addObserver(notifier -> { notifier.removeObserver(this); }); observable.change(); } } 

el error de comstackción es:

 The method removeObserver(Main.Observer) in the type Main.Observable is not applicable for the arguments (Main) 

Entonces mi pregunta es: ¿hay alguna manera de hacer referencia al “objeto lambda” con this ?

No puede hacer referencia a this en una expresión lambda. La semántica de this se ha cambiado para hacer referencia a la instancia de la clase circundante solamente, desde dentro de la lambda. No hay forma de hacer referencia a la expresión lambda desde dentro de la lambda.

El problema es que usas this en el método main() . El método principal es estático y no hay referencia a un objeto que lo represente.

Cuando usas this dentro de una instancia de una clase interna, estás haciendo referencia a la instancia de la clase interna. Una expresión lambda no es una clase interna, this no hace referencia a la instancia de la expresión lambda. Hace referencia a la instancia de la clase en la que define la expresión lambda. En su caso, sería una instancia de Main. Pero como estás en un método estático, no hay instancia.

Esto es lo que le está diciendo su segundo error de comstackción. Usted le entrega una instancia de Main a su método. Pero la firma de su método requiere una instancia de Observer.

Actualizar:

La Especificación del lenguaje Java 15.27.2 dice :

A diferencia del código que aparece en las declaraciones de clase anónimas, el significado de los nombres y las palabras clave this y super que aparecen en un cuerpo lambda, junto con la accesibilidad de las declaraciones referenciadas, son las mismas que en el contexto circundante (excepto que los parámetros lambda introducen nombres nuevos).

La transparencia de esto (tanto explícita como implícita) en el cuerpo de una expresión lambda, es decir, tratarla igual que en el contexto circundante, permite una mayor flexibilidad para las implementaciones y evita que el significado de los nombres no calificados en el cuerpo sea dependiente. en la resolución de sobrecarga.

Hablando en términos prácticos, es inusual que una expresión lambda necesite hablar sobre sí misma (ya sea para llamarse recursivamente o para invocar sus otros métodos), mientras que es más común querer usar nombres para referirse a cosas en la clase adjunta que lo haría de lo contrario, se sombreará ( this, toString () ). Si es necesario que una expresión lambda se refiera a sí misma (como a través de esto ), en su lugar se debe usar una referencia de método o una clase interna anónima.

Solución 1

Su método change() arroja ConcurrentModificationException todos modos.

 public class Main { public static void main(String[] args) { Observable observable = new Observable(); final Observer[] a = new Observer[1]; final Observer o = er -> er.removeObserver(a[0]); // !! a[0] = o; observable.addObserver(o); observable.change(); } } public class Observable { private final java.util.Collection n = java.util.new ArrayList<>(); public void addObserver(Observer notifiable) { n.add(notifiable); } public void removeObserver(Observer notifiable) { n.add(notifiable); } public void change() { for (final Observer o : n.toArray(new Observer[n.size()])) { o.changed(this); } } } public interface Observer { void changed(Observable notifier); } 

Solución 2

Cambié lo changed(Observable) a changed(Observable, Observer) para que un observador pueda manejarlo solo.

 public class Main { public static void main(String[] args) { Observable observable = new Observable(); final Observer o = (er, ee) -> er.removeObserver(ee); // !! observable.addObserver(o); observable.change(); } } public class Observable { private final java.util.Collection n = new java.util.ArrayList<>(); public void addObserver(Observer notifiable) { n.add(notifiable); } public void removeObserver(Observer notifiable) { n.add(notifiable); } public void change() { for (final Observer o : n.toArray(new Observer[n.size()])) { o.changed(this, o); } } } public interface Observer { void changed(Observable notifier, Observer notifiee); }