当前位置: 首页 > 知识库问答 >
问题:

Lambda java中的此引用

邹英悟
2023-03-14

我想将匿名类转换为lambda表达式。但是这个匿名类使用关键字this。

例如,我写了一个简单的观察者/可观察模式:

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

此示例代码包含一个匿名类(使用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();
    }
}

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

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对象?

共有2个答案

慕阳平
2023-03-14

您的change()方法无论如何都会抛出ConvoltModificationException

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

我将changed(Observable)更改为changed(Observable,observator),以便观察者可以处理自己。

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);
}
柯琛
2023-03-14

您不能在lambda表达式中引用thisthis的语义已更改为仅从lambda内部引用周围类的实例。无法从lambda内部引用lambda表达式的this

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

当您在内部类的实例中使用此时,您引用的是内部类的实例。lambda表达式不是内部类,它不是引用lambda表达式的实例。它引用的是在其中定义lambda表达式的类的实例。在您的情况下,它将是Main的一个实例。但由于您的方法是静态的,所以没有实例。

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

更新:

Java语言规范15.27.2规定:

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

lambda表达式主体中的透明性(包括显式和隐式),也就是说,将其视为与周围上下文中相同的内容,为实现提供了更大的灵活性,并防止主体中非限定名称的含义依赖于重载解析。

实际上,lambda表达式需要谈论自身(递归调用自身或调用其其他方法)是不常见的,而更常见的是希望使用名称来引用封闭类中可能会被隐藏的内容(这是toString())。如果lambda表达式需要引用自身(就像通过它一样),则应html" target="_blank">使用方法引用或匿名内部类。

 类似资料:
  • 我正在使用Mojang API从Minecraft玩家的用户名返回UUID。此方法在参数(我们想要知道UUID的播放器的用户名)中接受一个字符串。为了使用API的resultat,我使用SimpleJSON库(将JSON结果解析为要返回的字符串)。 我的方法抛出2个检查过的异常:IOExeption和Parse异常,因为我想要。当错误的用户名(因此不存在用户名)时,API返回一个空JSON对象,在

  • 在我的Visual studio 2015 update 3中,当我将解决方案文件夹复制到另一台windows计算机时,我遇到了以下错误。 错误此项目引用了此计算机上缺少的NuGet包。使用NuGet包还原来下载它们。如需详细资讯,请参阅http://go.microsoft.com/fwlink/?LinkID=322105.遗失的档案是..\包\Microsoft。net . compiler

  • 我已经检查了两个选项,允许nuget自动下载和安装丢失的包检查/打开。我也尝试删除包文件夹中的所有文件,然后让nuget重新下载它们。另外,当我打开nuget并寻找更新时,它说没有需要安装的更新。我想不出还能做什么来超越这个令人惊讶的烦人的问题。 我还通过右键单击项目并选择该选项来启用nuget还原。然后,它添加了一个nuget文件夹和该文件夹中的三个项目,并没有解决该问题。我试着重新构建,仍然得

  • 问题内容: 希望能帮助您理解“ Java并发实践”中的以下内容: 从构造函数中调用可重写的实例方法(既不是私有方法也不是final方法)也可以使this引用转义。 这里的“转义”是否仅表示在实例完全构建之前,我们可能正在调用实例方法? 我看不到“ this”以任何其他方式逃避了实例的范围。 ‘最终’如何防止这种情况的发生?我缺少实例创建中的’最终’某些方面吗? 问题答案: 这意味着在类之外调用代码

  • 在此代码中,我有以下警告: 用方法引用替换此lambda。 我不知道如何解决这个错误,因为它在forEach中,在map中,我可以使用,但在这里,我不能。 有什么想法吗?