在 Java 8 中分配多个 JCheckBox 侦听器的冗余方式较少? (例如方法参考?)

Less redundant way to assign several JCheckBox listeners in Java 8? (E.g. method reference?)

模式总是一样的:

示例代码:

jChecKBoxWindowSizeLocked.addActionListener(e -> {
    final WindowConfig lastWin = getLastTouchedWindowConfig();
    if (lastWin != null) {
        lastWin.setSizeLocked(jChecKBoxWindowSizeLocked.isSelected());
    }
});
jChecKBoxRememberSize.addActionListener(e -> {
    final WindowConfig lastWin = getLastTouchedWindowConfig();
    if (lastWin != null) {
        lastWin.setRememberSize(jChecKBoxRememberSize.isSelected());
    }
});
etc.

这看起来非常多余,好像它应该可以用 Lambda 或方法解决,但是我如何在没有确定 object Y 的情况下提供对方法 Z 的引用?我试过这个方法,但我使用的调用可能不正确:

private void addCheckboxListener(final JCheckBox checkBox, final Consumer<Boolean> setter) {
    checkBox.addActionListener(e -> {
        if (setter != null) {
            setter.accept(checkBox.isSelected());
        }
    });
}

来电是:

addCheckboxListener(cbRememberSize, getLastTouchedWindowConfig()::setRememberSize);

我很确定这会在调用 add 方法时提供对 getter returns 的任何引用,而不是稍后解析的一般引用。因此,这会在其自己的行中导致 NullPointerException(但编译得很好):

addCheckboxListener(cbRememberLocation, ((WindowConfig) null)::setRememberLocation);

当然,我可以只给出通过反射声明的目标 class' setter 方法,但是对于大约 10 个 JCheckBoxes 来说,这完全是矫枉过正。现在,如果它只是大约 10,那么我应该只是复制代码而不是扮演科学家,对吧。

但是我的 point/question 认为应该有某种 Lambda-ish method-reference-y 的方法来完成这项工作。还是这种可能性确实不存在?





编辑





感谢 Holger 的回复,我现在成功地尝试使用具有附加实例参数的静态 setters,这样 addCheckboxListener 就可以采用 static 方法引用因此按预期工作。 (EDIT2: 不。不是静态的。请参阅对 Holger(已接受)回复的评论。"EDIT" 部分的其余部分是在此 EDIT2 之前编写的。)

我不乐意让 setters 静态化,但目前这似乎是最优雅的解决方案,而且它肯定是一把放在工具棚里的好刀。

一个新的problem/question由此产生。在我可能就此发表新的 post 之前,我会在这里提问:

本次调用出现无法解释的编译错误:

addCheckboxListener(jCheckBoxRememberLocation, WindowConfig::setRememberLocation);

方法的头部:

private void addCheckboxListener(JCheckBox checkBox, BiConsumer<WindowConfig, Boolean> setter) {

错误:

Error:(72, 49) java: incompatible types: invalid method reference
reference to setRememberLocation is ambiguous
both method setRememberLocation(WindowConfig,Boolean) in WindowConfig and method setRememberLocation(boolean) in WindowConfig match

只有当我在 WinConfig class 中同时拥有旧的 non-static setter 和新的静态 setter 时才会出现错误,而且它们都需要有一组不同的参数。 这可能是 Java 错误吗? 以下是方法:

public void setRememberLocation(final boolean rememberLocation) {
    this.rememberLocation = rememberLocation;
}

public static void setRememberLocation(final WindowConfig instance, final Boolean rememberLocation) {
    instance.rememberLocation = rememberLocation;
}

错误似乎是错误的,因为两种方法中只有一种符合配置文件。

真正奇怪的是:如果我将 non-static 方法的头部更改为与静态方法的头部完全相同,错误就会消失。

但是 REALLY 超级奇怪的是:如果我然后交换 non-static 方法的第一个和第二个参数,错误仍然不会发生。 WTF!?

C:\>java -version
java version "1.8.0_74"
Java(TM) SE Runtime Environment (build 1.8.0_74-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode)

C:\Program Files\Java\jdk1.8.0_74\bin>javac -version
javac 1.8.0_74

winver
Windows 7 Ultimate
Version 6.1 (Build 7601: Service Pack 1)

项目使用了 Java 版本。它也是我系统上唯一的一个。 (不,其他地方也没有 32 位版本。)

显然你想要这样的方法:

private void addCheckboxListener(
    JCheckBox checkBox, BiConsumer<WindowConfig, Boolean> setter) {

    Objects.requireNonNull(setter);
    checkBox.addActionListener(e -> {
        final WindowConfig lastWin = getLastTouchedWindowConfig();
        if(lastWin != null) {
            setter.accept(lastWin, checkBox.isSelected());
        }
    });
}

您可以将其调用为

addCheckboxListener(cbRememberSize,     WindowConfig::setRememberSize);
addCheckboxListener(cbRememberLocation, WindowConfig::setRememberLocation);

应该在其上调用该方法的 WindowConfig 实例成为功能签名的一部分,并将在事件发生时获取并传递给该功能。

请注意,我将行为更改为立即拒绝 null setter 参数,而不是默默地忽略此类错误条件。