Java: setCellValuefactory; Lambda vs. PropertyValueFactory; advantages/disadvantages
PropertyValueFactory
expects correctly named property getters. getAColumnsProperty
is probably not one.
In case of new PropertyValueFactory<Appointment, LocalDate>("date")
the Appointment
class needs to contain a dateProperty()
method; the returned values need to extend ReadOnlyProperty
for this to work and any edits will only lead to an update in the model automatically, if the returned object also WritableValue
.
Example Appointment
class that should work with PropertyValueFactory<>("date")
:
public class Appointment {
private final ObjectProperty<LocalDate> date = new SimpleObjectProperty<>();
public final LocalDate getDate() {
return this.date.get();
}
public final void setDate(LocalDate value) {
this.date.set(value);
}
public final ObjectProperty<LocalDate> dateProperty() {
return this.date;
}
}
If no such method exists, PropertyValueFactory
will use a getter to retrieve the value, i.e. getDate()
, but this case updates in the model will not be visible in the UI until it updates the Cell
, since the PropertyValueFactory
"does not know" where to add a listener.
Disadvantages of PropertyValueFactory
- Can only find
public
methods in apublic
class -
PropertyValueFactory
uses reflection - Not typesafe. In
new PropertyValueFactory<Appointment, LocalDate>("date")
the compiler does not check, if there is a appropriate method, if that method even returns a suitable class or if e.g. the property getter returns aString
instead of aReadOnlyProperty<LocalDate>
which can lead toClassCastException
s. - No compile time checking. In the lambda expression the compiler can do some checking if the method exists and returns a appropriate type; with
PropertyValueFactory
this is not done. - Does not work with records.
If you are sure to implement the appropriate methods in the item class correctly, there is nothing wrong with using PropertyValueFactory
, but as mentioned above it has it's disadvantages. Moreover implementing the Callback
is much more flexible. You could e.g. do some additional modifications:
TableColumn<Appointment, String> column = ...
column.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Appointment, String>, ObservableValue<String>> {
@Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<Appointment, String> cd) {
Appointment a = cd.getValue();
return Bindings.createStringBinding(() -> "the year: " + a.getDate().getYear(), a.dateProperty());
}
});