我正在自己研究Oracle的JavaFX教程。在做Swing多年(很久以前)之后,我对新的智能功能着迷,包括。特性。我很惊讶地看到这些示例(例如https://docs.oracle.com/javafx/2/ui_controls/table-view.htm)没有以我认为“正确”的方式使用它们。

该示例创建一个带有属性作为字段的Person类:

public static class Person {
    private final SimpleStringProperty firstName;
    ...

但是, setter/getter 不是针对属性,而是针对其值
    public String getFirstName() {
        return firstName.get();
    }

因此,当将它们绑定(bind)到列中的TableCell时,它将它们包装在新属性中:
    emailCol.setCellValueFactory(
            new PropertyValueFactory<Person, String>("firstName"));

这在我看来是令人费解的,并且错过了事件传播的真正优势,因为它并非简单地使用以下方法:
    firstNameCol.setCellValueFactory( celldata ->
        celldata.getValue().firstNameProperty());

我的问题:这个示例为什么没有直接在控件中公开和使用bean的属性,这是有原因的吗?我在这里想念什么吗?

注意:我确实以这种方式更改了代码,该示例的效果更好:通过其他控件立即传播Person实体中的更新,而无需调用table.refresh(),例如

最佳答案

首先,请注意,如果您遵循expected pattern:

public class Person {

    private final StringProperty firstName = new SimpleStringProperty();

    public StringProperty firstNameProperty() {
        return firstName ;
    }

    public final String getFirstName() {
        return firstNameProperty().get();
    }

    public final void setFirstName(String firstName) {
        firstNameProperty().set(firstName);
    }
}

那么您的任何一个版本的代码都可以工作,而无需调用table.refresh()。这是PropertyValueFactory的预期用途,从documentation可以很明显地看出来。

不过,您是正确的,lambda表达式比PropertyValueFactory更好。除了您引用的原因外,与PropertyValueFactory相比,使用lambda表达式还有其他主要优势。首先,也是最重要的一点,PropertyValueFactory只是将属性的名称作为String,这意味着没有针对它的编译时检查。因此,如果您拼写错误的属性名称:
firstNameCol.setCellValueFactory(new PropertyValueFactory<>("firstname"));

这样可以很好地编译,并且您最终只会在该列中留空单元格。这可能很难调试(正如该网站上针对此类错误寻求帮助的问题数量所证明的那样)。

其次,PropertyValueFactory通过反射起作用,这比lambda表达式慢得多。这可能导致可测量的性能差异,例如在对具有大量数据的表进行排序时。

引入PropertyValueFactory的原因基本上是历史性的。在Java 8之前,当然没有lambda表达式,因此没有此便利类的单元工厂的最小实现是通过匿名内部类:
firstNameCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person, String>, ObservableValue<String>>() {
    @Override
    public ObservableValue<String> call(TableColumn.CellDataFeatures<Person, String> cellData) {
        return cellData.getValue().firstNameProperty();
    }
});

由于该代码确实非常丑陋,因此JavaFX团队引入了PropertyValueFactory只是为了使该API易于使用。

当使用Java 8及更高版本时,PropertyValueFactory实际上应被视为旧类,并且应首选lambda表达式。当然,早于Java 8的文档也仍然存在(实际上,您明确地从JavaFX 2链接了文档-尽管Javafx PropertyValueFactory not populating Tableview尚未更新),并且-坦率地说-太多其他作者复制了该文档。样式,没有经过适当考虑。完全弃用PropertyValueFactory类可能是一个很好的案例。

(所以:TL; DR:不,您没有丢失任何东西。)

09-05 08:13