如何移除用作监听器的Lambda表达式/方法句柄?

11

Java 8 引入了Lambda表达式,这是一个很好的功能。但现在考虑重写以下代码:

class B implements PropertyChangeListener {
    void listenToA(A a) {
        a.addPropertyChangeListener(this);
    }

    void propertyChange(PropertyChangeEvent evt) {
        switch(evt.getPropertyName()) {
            case "Property1":
                doSomething();
                break;
            case "Property2":
                doSomethingElse();                case "Property1":
                doSomething;
                break;

                break;
    }

    void doSomething() { }
    void doSomethingElse() { }
}

class A {
    final PropertyChangeSupport pcs = new PropertyChangeSupport(this);

    void addPropertyChangeListener(PropertyChangeListener listener) {
        pcs.addPropertyChangeListener(listener);
    }

    void removePropertyChangeListener(PropertyChangeListener listener) {
        pcs.removePropertyChangeListener(listener);
    }
}

使用 lambda 表达式和方法引用,不再需要让 B 实现 PropertyChangeListener 接口,因为我们可以这样写:

class B {
    void listenToA(A a) {
        // using method reference
        a.addPropertyChangeListener("Property1", this::doSomething);
        // using lambda expression
        a.addPropertyChangeListener("Property2", e -> doSomethingElse());
    }

    void doSomething(PropertyChangeEvent evt) { }
    void doSomethingElse() { }
}

class A {
    final PropertyChangeSupport pcs = new PropertyChangeSupport(this);

    void addPropertyChangeListener(String name, PropertyChangeListener listener) {
        pcs.addPropertyChangeListener(name, listener);
    }

    void removePropertyChangeListener(String name, PropertyChangeListener listener) {
        pcs.removePropertyChangeListener(name, listener);
    }
}

我认为新代码不仅更短,而且更清晰易懂。但是在阅读这里给出的答案后(与这个问题的重复,但我认为问题和答案更简洁),我看不到实现名为stopListening()的方法来移除侦听器的方法。

我相信我不是第一个遇到这个问题的人。那么有没有人发现了一个好的解决方案,可以像这个示例中显示的那样使用方法句柄,并且仍然能够稍后再次删除侦听器呢?

更新

很快就有结果了。在借鉴Mike Naklis和Hovercraft Full Of Eels的答案的基础上,我最终得到了以下内容:

class B {
    void listenToA(A a) {
        a.addPropertyChangeListener("Property1", doSomething);
        a.addPropertyChangeListener("Property2", doSomethingElse);
    }

    final PropertyChangeListener doSomething = evt -> {};
    final PropertyChangeListener doSomethingElse = evt -> {};
}

不要声明一个方法,而是声明一个带有lambda表达式的函数对象。在多种情况下,这是一种有用的策略。 - ZhongYu
然而,需要考虑该函数(即功能对象)是否可以是静态的(在这种情况下,是的)。如果每个对象都有自己的函数实例,那么可能会浪费内存。 - ZhongYu
@ZhongYu 谢谢。但是由于监听器必须与它们所属的 B 实例有关,我不能在我的程序中将它们设为静态的。 - Axel
evt.source是什么? - ZhongYu
那将会是 A - Axel
2个回答

12

您可以按以下方式声明监听器:

private final PropertyChangeListener myProperty1Listener = this::doSomething;
private final PropertyChangeListener myProperty2Listener = e -> doSomethingElse());

然后,您可以添加您的监听器:

// using method reference
a.addPropertyChangeListener( "Property1", myProperty1Listener );
// using lambda expression
a.addPropertyChangeListener( "Property2", myProperty2Listener );

你可以将它们移除:

a.removePropertyChangeListener( "Property1", myProperty1Listener );
a.removePropertyChangeListener( "Property2", myProperty2Listener );

1
你比我打得快,我还没来得及输入(1+) - Hovercraft Full Of Eels

2

您可以使用lambda表达式并仍然使用变量。例如,如果您有:

class B {
    private PropertyChangeListener listener1 = this::doSomething;
    private PropertyChangeListener listener2 = e -> doSomethingElse(); 

    void listenToA(A a) {
        // using method reference
        a.addPropertyChangeListener("Property1", listener1);
        // using lambda expression
        a.addPropertyChangeListener("Property2", listener2);
    }

当需要时,删除listener1或listener2将变得很容易。

此外,还有其他方法,因为PropertyChangeSupport对象具有getPropertyChangeListeners()方法,如果需要,可以在for循环中删除所有侦听器。

class A {
    final PropertyChangeSupport pcs = new PropertyChangeSupport(this);

    void addPropertyChangeListener(String name, PropertyChangeListener listener) {
        pcs.addPropertyChangeListener(name, listener);
    }

    void removePropertyChangeListener(String name, PropertyChangeListener listener) {
        pcs.removePropertyChangeListener(name, listener);
    }

    public void removeAllListeners() {
        for (PropertyChangeListener l : pcs.getPropertyChangeListeners()) {
            pcs.removePropertyChangeListener(l);
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接