Skip to content

Instantly share code, notes, and snippets.

@james-d
Last active December 6, 2022 08:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save james-d/8602638 to your computer and use it in GitHub Desktop.
Save james-d/8602638 to your computer and use it in GitHub Desktop.
The Bindings.select*(...) family of methods use try-catch to implement null checking of "intermediate" properties. This is highly inefficient, as demonstrated by this example. Sort by the "Zip" column to see the problem.
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableWithSelectBinding extends Application {
private static final int NUM_ROWS = 1_000_000 ;
private static final Random RNG = new Random();
@Override
public void start(Stage primaryStage) {
final TableView<Person> table = new TableView<>();
final TableColumn<Person, String> nameCol = new TableColumn<>("Name");
final TableColumn<Person, String> zipCol = new TableColumn<>("Zip");
nameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("name"));
zipCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person,String>, ObservableValue<String>>() {
@Override
public ObservableValue<String> call(CellDataFeatures<Person, String> cdf) {
Person person = cdf.getValue();
// Bindings.selectString uses try{}catch(){} for logical checking of null values
// This is inefficient enough to hang this example on sorting with 1,000,000 rows
return Bindings.selectString(person.addressProperty(), "zip");
// The following is an incomplete implementation
// (will not update if Person.addressProperty changes)
// but uses proper null checking and consequently runs much faster:
// Address address = person.getAddress();
// if (address == null) {
// return new ReadOnlyStringWrapper("");
// } else {
// return address.zipProperty() ;
// }
}
});
table.getColumns().addAll(nameCol, zipCol);
table.setItems(createData());
final BorderPane root = new BorderPane();
root.setCenter(table);
final Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private ObservableList<Person> createData() {
List<Person> data = new ArrayList<Person>();
for (int i=0; i<NUM_ROWS; i++) {
data.add(new Person(randomString(), null));
}
return FXCollections.observableArrayList(data);
}
private String randomString() {
StringBuilder sb = new StringBuilder();
for (int i=0; i<=8; i++) {
sb.append((char) ('a' + RNG.nextInt(26)));
}
return sb.toString();
}
public static void main(String[] args) {
launch(args);
}
public static class Person {
private final StringProperty name ;
private final ObjectProperty<Address> address ;
public Person(String name, Address address) {
this.name = new SimpleStringProperty(this, "name", name);
this.address = new SimpleObjectProperty<Address>(this, "address", address);
}
public final String getName() {
return name.get();
}
public final void setName(String name) {
this.name.set(name);
}
public final StringProperty nameProperty() {
return name ;
}
public final Address getAddress() {
return address.get();
}
public final void setAddress(Address address) {
this.address.set(address);
}
public final ObjectProperty<Address> addressProperty() {
return address ;
}
}
public static class Address {
private final StringProperty zip ;
// other properties omitted
public Address(String zip) {
this.zip = new SimpleStringProperty(this, "zip", zip);
}
public final String getZip() {
return zip.get();
}
public final void setZip(String zip) {
this.zip.set(zip);
}
public final StringProperty zipProperty() {
return zip ;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment