Logo Questions Linux Laravel Mysql Ubuntu Git Menu

JavaFx tableview sort is really slow how to improve sort speed as in java swing

I am working on javaFx application and have created a tableview and have around 100,000+ rows with 10 columns.

I have also created same table using java swing Jtable.

Now I need sorting performance to be better in javaFx if not better than some what near to java swing's jtable.

Right Now I am using sortorder() which sort data by clicking on column headers and sort speed is 20 times slower than Jtable.

Can anyone please help ?

Thank You


I am using example 13.8 in this link http://docs.oracle.com/javafx/2/ui_controls/table-view.htm just has added few line of code to just add 100,000 rows by generating random data.

like image 438
learner Avatar asked Mar 24 '23 19:03


1 Answers

It took a while, but I think I have figured this out, at least for this example.

In this example, the Person class doesn't have any property accessors (i.e. there's a getFirstName() method, but no firstNameProperty() method). Sorting by columns has to access the value in each cell in the column via the cell value factory. When there's no property accessor, the cell value factory is going to call getFirstName() and then wrap the result in a new ReadOnlyObjectWrapper on each invocation.

If you make sure the class representing the row data has the appropriate property accessors, then retrieving the value is much more efficient, as it merely returns a reference to the existing StringProperty.

This example sorts 100,000 rows in approximately a second on my system (MacBookPro 8GB RAM, quad core). You can improve performance more by providing an explicit cell value factory, which gets around the need for reflection in computing the cell value. In other words, replace

            new PropertyValueFactory<Person, String>("firstName"));


    firstNameCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person,String>, ObservableValue<String>>() {
      public ObservableValue<String> call(CellDataFeatures<Person, String> cdf) {
        return cdf.getValue().firstNameProperty();

The performance saving here is not as dramatic.

Here's the full example:

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;

import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Random;

public class TableSortPerformanceTest extends Application {

    public static void main(String[] args) {

    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");

        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));

        final TableView<Person> table = new TableView<Person>();

        TableColumn<Person, String> firstNameCol = new TableColumn<Person, String>("First Name");
                new PropertyValueFactory<Person, String>("firstName"));
        firstNameCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person,String>, ObservableValue<String>>() {
          public ObservableValue<String> call(CellDataFeatures<Person, String> cdf) {
            return cdf.getValue().firstNameProperty();

        TableColumn<Person, String> lastNameCol = new TableColumn<Person, String>("Last Name");
                new PropertyValueFactory<Person, String>("lastName"));

        TableColumn<Person, String> emailCol = new TableColumn<Person, String>("Email");
                new PropertyValueFactory<Person, String>("email"));

        Random random = new Random();
        for (int i = 0; i < 100000; i++) {
          table.getItems().add(new Person(randomString(random), randomString(random), randomString(random)));
        table.getColumns().addAll(Arrays.asList(firstNameCol, lastNameCol, emailCol));

        long start = new Date().getTime();
        long end   = new Date().getTime();
        System.out.println("Took: " + (end - start));

        final TextField addFirstName = new TextField();
        addFirstName.setPromptText("First Name");
        final TextField addLastName = new TextField();
        addLastName.setPromptText("Last Name");
        final TextField addEmail = new TextField();

        final Button addButton = new Button("Add");
        addButton.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent e) {
                table.getItems().add(new Person(

        final HBox hb = new HBox(3);
        hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton);

        final VBox vbox = new VBox();
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, table, hb);

        ((Group) scene.getRoot()).getChildren().addAll(vbox);


    private String randomString(Random random) {
      char[] chars = new char[20];
      for (int i = 0; i < 20; i++) {
        int nextInt = random.nextInt(26);
        nextInt += random.nextBoolean() ? 65 : 97;
        chars[i] = (char) nextInt;
      return new String(chars);

    public static class Person implements Comparable<Person> {

        private final StringProperty firstName;
        private final StringProperty lastName;
        private final StringProperty email;

        private Person(String fName, String lName, String email) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);

        public String getFirstName() {
            return firstName.get();

        public void setFirstName(String fName) {

        public StringProperty firstNameProperty() {
          return firstName ;

        public String getLastName() {
            return lastName.get();

        public void setLastName(String fName) {

        public StringProperty lastNameProperty() {
          return lastName ;

        public String getEmail() {
            return email.get();

        public void setEmail(String fName) {

        public StringProperty emailProperty() {
          return email ;

    public int compareTo(Person o) {
      return firstName.get().compareTo(o.getFirstName());

UPDATE: Note this is fixed in JavaFX 8.

like image 151
James_D Avatar answered Apr 07 '23 13:04