method - java:: operator
Lambda esta referencia en java (2)
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<Observer> 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<Observer> 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);
}
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<Observer> 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 compilació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 compilació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 compilació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.