I'm working through myself Oracle's JavaFX tutorials. After doing Swing for many years (a long time ago) I'm fascinated by the new smart features, incl. properties. I was surprised to see that these examples (e.g: https://docs.oracle.com/javafx/2/ui_controls/table-view.htm) don't use them in a way what I believe to be "proper".
The example creates a Person
class with properties as fields:
public static class Person {
private final SimpleStringProperty firstName;
...
But the getters are not for the properties, but for their values
public String getFirstName() {
return firstName.get();
}
so when it binds those to TableCell
s in columns, it wraps them in a new property:
emailCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));
This seems convoluted to me, and misses the real advantage of event propagation, by not simply using this:
firstNameCol.setCellValueFactory( celldata ->
celldata.getValue().firstNameProperty());
My question: Is there a reason why this example doesn't expose and use the bean's properties in the control directly? Am I missing something here?
NB: I did change the code this way, and the example worked much nicer: updates in the Person
entity by an other control were propagated immediately, w/o calling table.refresh()
e.g.
First, note that if you follow the 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);
}
}
then either version of your code will work without calling table.refresh()
. This was the intended use of PropertyValueFactory
, as is fairly clear from the documentation.
You are correct, though, that the lambda expression is a better approach than the PropertyValueFactory
. Besides the reasons you cite, there are other major advantages to using the lambda expression over PropertyValueFactory
. First, and most importantly, the PropertyValueFactory
simply takes the name of the property as a String
, meaning that there is no compile-time check for it. So if you were to misspell the name of the property:
firstNameCol.setCellValueFactory(new PropertyValueFactory<>("firstname"));
this would compile just fine, and you would simply end up with blank cells in the column. This can be quite hard to debug (as is evidenced by the number of questions on this site asking for help with this kind of bug: e.g. Javafx PropertyValueFactory not populating Tableview).
Secondly, the PropertyValueFactory
works by reflection, which is much slower than a lambda expression. This can lead to measurable performance differences, for example in sorting a table with a large amount of data.
The reason PropertyValueFactory
was introduced is basically historical. Prior to Java 8, there were of course no lambda expressions, so the minimal implementation of the cell factory without this convenience class was via an anonymous inner class:
firstNameCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person, String>, ObservableValue<String>>() {
@Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<Person, String> cellData) {
return cellData.getValue().firstNameProperty();
}
});
Since that code is really quite hideous, the JavaFX team introduced the PropertyValueFactory
simply as a way to make the API easier to use.
When using Java 8 and later, PropertyValueFactory
should really be considered a legacy class, and the lambda expression should be preferred. Of course, documentation that predates Java 8 also still exists (in fact, you explicitly link documentation from JavaFX 2 - though the most recent version still hasn't been updated), and there are - to be frank - far too many other writers who copy that style without properly thinking it through. There is probably a good case to be made for deprecating the PropertyValueFactory
class entirely.
(So: TL;DR: no, you're not missing anything.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With