Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I remove lambda expressions/method handles that are used as listeners?

Java 8 has introduced lambda expressions, which is a great thing. But now consider rewriting this code:

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

With lambda expressions and method references, it is no more necessary to have B implement PropertyChangeListner as we can write

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

I think the new code is not only shorter but also cleaner and easier to understand. But after reading the answers given here (duplicate of this one, but I think question and answer are more crisp), I can see no way to implement a method called stopListening() which would remove the listeners again.

I am sure that I am not the first one to stumble on this. So has anyone found a nice solution on how to use method handles as shown in this example and still being able to remove the listeners again later?

UPDATE

That was fast. Building on the answers by Mike Naklis and Hovercraft Full Of Eels, I ended up with this:

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

    final PropertyChangeListener doSomething = evt -> {};
    final PropertyChangeListener doSomethingElse = evt -> {};
}
like image 364
Axel Avatar asked Feb 09 '17 20:02

Axel


People also ask

How do you replace lambda expression with method reference?

If you are using a lambda expression as an anonymous function but not doing anything with the argument passed, you can replace lambda expression with method reference. In the first two cases, the method reference is equivalent to lambda expression that supplies the parameters of the method e.g. System.

What is the difference between a lambda expression and a method?

Lambda expression is an anonymous method (method without a name) that has used to provide the inline implementation of a method defined by the functional interface while a method reference is similar to a lambda expression that refers a method without executing it.

How do you convert lambda expression to method?

To make the code clearer, you can turn that lambda expression into a method reference: Consumer<String> c = System. out::println; In a method reference, you place the object (or class) that contains the method before the :: operator and the name of the method after it without arguments.

Can we change the lambda expression variable data?

Yes, you can modify local variables from inside lambdas (in the way shown by the other answers), but you should not do it.


2 Answers

You can declare your listeners as follows:

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

then, you can add your listeners:

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

and you can remove them:

a.removePropertyChangeListener( "Property1", myProperty1Listener );
a.removePropertyChangeListener( "Property2", myProperty2Listener );
like image 74
Mike Nakis Avatar answered Sep 24 '22 02:09

Mike Nakis


You can use lambdas and still use variables. For example, if you had:

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

Then it would be easy to remove listener1 or listener2 when and where needed.

Also there are other ways, since the PropertyChangeSupport object has a getPropertyChangeListeners() that would allow removal of all listeners in a for loop if need be.

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);
        }
    }
}
like image 26
Hovercraft Full Of Eels Avatar answered Sep 21 '22 02:09

Hovercraft Full Of Eels