当前位置: 首页 > 知识库问答 >
问题:

为什么我应该避免在JavaFX中使用PropertyValueFactory?

闾丘鸣
2023-03-14

对于与PropertyValueFactory相关的问题,许多回答(和评论)建议避免使用该类和其他类似类。使用这个类有什么问题?

共有1个答案

赵嘉赐
2023-03-14

TL;博士:

>

  • 您应该避免使用PropertyValueFactory和类似的类,因为它们依赖于反射,更重要的是,会导致您丢失有用的编译时验证(例如,如果属性确实存在)。

    用lambda表达式替换PropertyValueFactory的使用。例如,替换:

    nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
    

    与:

    nameColumn.setCellValueFactory(data -> data.getValue().nameProperty());
    

    (假设您使用的是Java8,并且您已经定义了模型类来公开JavaFX属性)

    这门课,以及其他类似的课程,是一门方便的课程。JavaFX是在Java 7时代(如果不是更早的话)发布的。当时,lambda表达式不是语言的一部分。这意味着JavaFX应用程序开发人员必须在任何时候创建一个匿名类,只要他们想设置表列的cellValueFactory。它看起来像这样:

    // Where 'nameColumn' is a TableColumn<Person, String> and Person has a "name" property
    nameColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person>, ObservableValue<String>>() {
    
      @Override
      public ObservableValue<String> call(TableColumn.CellDataFeatures<Person> data) {
        return data.getValue().nameProperty();
      }
    });
    

    如您所见,这非常冗长。想象一下对5列、10列或更多列做同样的事情。因此,JavaFX的开发人员添加了便利类,例如Property tyValueFactory,允许将上述内容替换为:

    nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
    

    但是,使用Property tyValueFactory和类似的类有其自身的缺点。这些缺点是:

    1. 依靠反射,而
    2. 丢失编译时验证。

    这是两个缺点中较小的一个,尽管它直接导致了第二个缺点。

    PropertyValueFactory将属性的名称作为字符串。然后,它可以调用模型类的方法的唯一方法是通过反射。如果可以的话,您应该避免依赖反射,因为反射会增加一层间接性并减慢速度(不过在这种情况下,性能影响可能可以忽略不计)。

    反射的使用还意味着您必须依赖编译器无法执行的约定。在这种情况下,如果您不完全遵循JavaFX属性的命名约定,那么实现将无法找到所需的方法,即使您认为它们存在。

    由于PropertyValueFactory依赖于反射,Java只能在运行时验证某些东西。更具体地说,编译器无法在编译期间验证属性是否存在,或者属性是否为正确的类型。这使得开发代码更加困难。

    假设您有以下模型课程:

    /*
     * NOTE: This class is *structurally* correct, but the method names
     *       are purposefully incorrect in order to demonstrate the
     *       disadvantages of PropertyValueFactory. For the correct
     *       method names, see the code comments above the methods.
     */
    public class Person {
    
      private final StringProperty name = new SimpleStringProperty(this, "name");
    
      // Should be named "setName" to follow JavaFX property naming conventions
      public final void setname(String name) {
        this.name.set(name);
      }
     
      // Should be named "getName" to follow JavaFX property naming conventions
      public final String getname() {
        return name.get();
      }
    
      // Should be named "nameProperty" to follow JavaFX property naming conventions
      public final StringProperty nameproperty() {
        return name;
      }
    }
    

    有这样的东西就可以编译了:

    TableColumn<Person, Integer> nameColumn = new TableColumn<>("Name");
    nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
    nameColumn.setCellFactory(tc -> new TableCell<>() {
    
      @Override 
      public void updateItem(Integer item, boolean empty) {
        if (empty || item == null) {
          setText(null);
        } else {
          setText(item.toString());
        }
      }
    });
    

    但是在运行时会有两个问题。

    >

  • Property tyValueFactory将无法找到“name”属性,并将在运行时抛出异常。这是因为Person的方法不遵循属性命名约定。在这种情况下,它们未能遵循camelCase模式。方法应该是:

    • 获取名称→ <代码>获取名称

    修复此问题将修复此错误,但随后会遇到第二个问题。

    updateItem(整数项,布尔值为空)的调用将抛出一个ClassCastException,表示String不能转换为整数。我们“意外”(在这个人为的示例中)创建了一个表格列

    您应该用lambda表达式替换PropertyValueFactory的用法,lambda表达式是在版本8中添加到Java语言中的。

    由于回调是一个函数接口,因此可以将其用作lambda表达式的目标。这允许您编写以下内容:

    // Where 'nameColumn' is a TableColumn<Person, String> and Person has a "name" property
    nameColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person>, ObservableValue<String>>() {
    
      @Override
      public ObservableValue<String> call(TableColumn.CellDataFeatures<Person> data) {
        return data.getValue().nameProperty();
      }
    });
    

    作为这:

    nameColumn.setCellValueFactory(data -> data.getValue().nameProperty());
    

    它基本上与Property tyValueFactory方法一样简洁,但没有上面讨论的任何缺点。例如,如果您忘记定义Person#nameProperty(),或者如果它没有返回观察力值

    lambda表达式甚至为您提供了更多自由,例如能够使用表达式绑定。

    有一个缺点,尽管它很小。

    “数字属性”,例如ENTgerPropertyDoubleProperty,都实现了观察力值

    >

  • 使用数字作为列的值类型,而不是整数。这并不太糟糕,因为您可以根据需要调用,例如,Number#intValue()

    或者使用例如,IntegerProperty#asObject(),它返回一个ObjectProperty

    column.setCellValueFactory(data -> data.getValue().someIntegerProperty().asObject());
    

    如果您使用的是Kotlin,那么lambda可能看起来像这样:

    nameColumn.setCellValueFactory { it.value.nameProperty }
    

    假设您在模型类中定义了适当的Kotlin属性。有关详细信息,请参阅此堆栈溢出答案。

    如果数据是只读的,那么可以使用记录,这是一种特殊的类。

    对于记录,不能使用PropertyValueFactory,必须使用自定义单元格值工厂(例如lambda)。

    记录访问器方法的命名策略不同于标准的JavaBeans命名策略。例如,对于名为name的成员,PropertyValueFactory使用的标准JavaBeans访问器名称将是getName(),但对于记录,name成员的访问器仅为name()。由于记录不遵循PropertyValueFactory所需的命名约定,因此不能使用PropertyValueFactory访问存储在记录中的数据。

    然而,这个答案中详细介绍的lambda方法将能够很好地访问记录中的数据。

    有关在TableView中使用带有单元格值工厂的记录的更多信息和示例,请访问:

    • 如何将JavaFX TableView与java记录一起使用?

  •  类似资料:
    • 问题内容: 一次又一次,我看到Bash在Stack Overflow上使用了答案,而答案被猛烈抨击了,旨在使用这种“邪恶的”构造。为什么这么邪恶? 如果不能安全使用,我应该怎么用呢? 问题答案: 这个问题比眼前的问题还重要。我们将从显而易见的内容开始:具有执行“脏”数据的潜力。脏数据是指尚未重写为XYZ的任何数据;在我们的例子中,它是未格式化的任何字符串,以确保评估安全。 乍看之下,对数据进行消毒

    • 本文向大家介绍为什么在Bash中应该避免eval,我应该用什么来代替呢?,包括了为什么在Bash中应该避免eval,我应该用什么来代替呢?的使用技巧和注意事项,需要的朋友参考一下 eval是Bash shell的内置命令,它将其参数连接为单个字符串。然后,它将参数与空格连接起来,然后将该字符串作为bash命令执行。以下是其工作方式的示例。 eval示例 在下面的示例中,我们使用一个字符串,该字符串

    • 问题内容: 有时是有用的,例如,如果我为网站上的所有链接(例如选择器)定义了通用样式,但是当我要覆盖某些规则时,可以有以下选择: 使用更具体(更长)的选择器 采用 哪种方法更好,可能有一些指导原则? 问题答案: 使用非常,非常谨慎- 它会覆盖刚才的一切,甚至是内联样式和混乱在低于显而易见的方式与样式规则“梯级”,让CSS的名字。它很容易使用不当,而且容易成倍增加,尤其是在滥用时。您可以轻松地得出一

    • 我的公司不允许使用Mockito。在单元测试中验证。甚至有一个定制的声纳规则 规则如下 应该通过断言来验证结果,而不是使用“验证到执行”过程验证。因为如果我们验证流程,在流程更改后需要更多的努力来维护测试,但输入和输出保持不变。确保每一行代码都对结果有影响,并断言结果以证明逻辑正确 不合规代码示例 合规解决方案 对于数据库或中间件操作,断言使用嵌入式数据库或中间件成功写入数据。 对于restful

    • 问题内容: Process p = Runtime.getRuntime().exec(command); is = p.getInputStream(); byte[] userbytes = new byte[1024]; is.read(userbytes); 我想从java在linux os中执行shell命令。但是Pmd报告说不要使用Java Runtime.exec()。为什么?是什么

    • 问题内容: 我读到应该避免赞成和。我对弄乱Loop并没有信心,也没有完全理解Codex。 下面的代码是否使用?如果是,并且由于应该避免,那么您能建议一种不使用但仍然完成相同任务的方法吗? 此代码用于按随机或按价格对帖子进行排序。 。 使用此代码将链接A(随机)和链接B(价格)发布在我的菜单中。因此,网站的访问者只需单击链接即可对帖子进行排序。 问题答案: 我已经针对WPSE这个主题做了非常详细的解