Search code examples
javajavafxchangelistener

Reference Method Change Listener not removed


When I add a change listener to an JavaFx Object Property by method reference and then try to remove that same change listener, it still seems to be registered as listener. Is this intended behaviour or a bug?

In the below example Hello World! is printed twice, I would expect it would print only once.

public class App {

public static void main(String[] args) {
    BooleanProperty b = new SimpleBooleanProperty(false);
    b.addListener(App::test);
    b.set(true);
    b.removeListener(App::test);
    b.set(false);
}

static void test(Object b, Object o, Object n) {
    System.out.println("Hello World!");
}
}

Solution

  • I have same result when running your code in debugger, which prints "Hello World!" twice.

    The listener lambda value App::test is resolved as reference to different instances of ChangeListener for each use, so that add/remove are not matched. Replace with a variable so that you pass same value in for each call:

    ChangeListener<? super Boolean> listener = App::test;
    b.addListener(listener);
    b.set(true);
    b.removeListener(listener);
    b.set(false);
    

    => Prints "Hello World!" once.

    Note comments by Louis Wasserman and user85421 for further explanation, and see also the JavaFX21+ workaround suggested by Slaw below which uses b.subscribe(Consumer|BiConsumer). Note that these consumer callbacks for subscribe do not pass in the source b which means you couldn't use same listener for multiple properties.