在Java中的lambda引用

我想将anonymous class转换为lambda expression 。 但是这个匿名类我使用this关键字。

例如,我写了这个简单的Observer/Observable模式:

 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); } 

和这个示例代码与匿名类(使用这个关键字):

 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(); } } 

但是当我将其转换为lambdaexpression式时:

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

我得到这个编译错误:

 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(); } } 

编译错误是:

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

所以我的问题是: 有没有办法引用这个“lambda对象”?

你不能在lambdaexpression式中引用this 。 这个语义已经被改变,只能从lambda内引用周围类的实例。 没有办法从lambda内部引用lambdaexpression式。

问题是你在main()方法中使用this 。 主要的方法是静态的,没有引用表示this的对象。

当你在一个内部类的实例中使用this时,你引用了内部类的实例。 lambdaexpression式不是内部类, this不是引用lambdaexpression式的实例。 它是引用到你定义lambdaexpression式的类的实例。在你的情况下,它将是一个Main的实例。 但是由于你是静态的,所以没有实例。

这是你的第二个编译错误告诉你的。 您将Main的一个实例移交给您的方法。 但是你的方法签名需要一个Observer实例。

更新:

Java语言规范说 :

在lambdaexpression式的主体中的透明性(即明确的和隐含的) – 也就是说,将其与周围的上下文一样处理 – 为实现提供了更大的灵活性,并且防止身体中非限定名称的含义依赖于在重载parsing上。

从实际的angular度讲,lambdaexpression式需要谈论自己(或者调用自己的recursion或者调用其他方法)是不常见的,而想要使用名称引用封闭类中的东西更常见否则被遮蔽( this,toString() )。 如果需要lambdaexpression式引用自身(就像通过这个 ),应该使用方法引用或匿名内部类。

解决方法1

无论如何,你的change()方法抛出ConcurrentModificationException

 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); } 

解决方法2

我改变了changed(Observable) changed(Observable, Observer)以便观察者可以自己处理。

 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); }