Lambda这个引用在java中

gon*_*ard 63 java lambda java-8

我想把一个转换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);
}
Run Code Online (Sandbox Code Playgroud)

这个带有匿名类的示例代码(使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

但是当我将它转换为lambda表达式时:

public class Main {

    public static void main(String[] args) {
        Observable observable = new Observable();
        observable.addObserver(notifier -> { notifier.removeObserver(this); });
        observable.change();
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到这个编译错误:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

编译错误是:

The method removeObserver(Main.Observer) in the type Main.Observable is not applicable for the arguments (Main)
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:有没有办法引用"lambda对象" this

Gre*_*lis 100

您无法this在lambda表达式中引用.语义this已被更改为仅从lambda内引用周围类的实例.无法this从lambda中引用lambda表达式.

问题是你thismain()方法中使用.main方法是static,没有引用表示的对象this.

当您this在内部类的实例中使用时,您将引用内部类的实例.lambda表达式不是内部类,this不引用lambda表达式的实例.它引用了您定义lambda表达式的类的实例.在您的情况下,它将是Main的一个实例.但是因为你是静态方法,所以没有实例.

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

更新:

Java语言规范15.27.2说:

与出现在匿名类声明中的代码不同,名称的含义以及出现在lambda主体中的this和super关键字以及引用声明的可访问性与周围上下文中的相同(除了lambda参数引入新名称).

lambda表达式主体中的这个(显式和隐式)的透明度- 也就是说,将其视为与周围上下文相同 - 允许实现更灵活,并防止身体中不合格名称的含义依赖关于重载决议.

实际上,lambda表达式需要谈论自身(要么递归地调用自身还是调用其他方法)是不寻常的,而更常见的是想要使用名称来引用封闭类中的内容.否则被遮蔽(this,toString()).如果lambda表达式需要引用它自己(就好像通过这个),则应该使用方法引用或匿名内部类.