gpt4 book ai didi

java - 当我切换到 GlazedLists 的 EventTableModel 时,为什么我的 JXTable 排序如此之慢?

转载 作者:塔克拉玛干 更新时间:2023-11-02 07:52:42 25 4
gpt4 key购买 nike

已更新

我已经更新了这个问题以更准确地描述我的问题的原因,并包含了一个比我最初使用的更简单的例子。

我在下面提供了一个简单示例来说明我遇到的性能问题。当我用普通的 ArrayList 支持我的 JXTable 时,它​​的表现相当不错。但是,如果我将 ArrayList 切换为 EventList 并使用 EventTableModel 构建表,排序会慢得多(在这种情况下慢 ~10 倍)。

如果使用 Maven 或 Gradle,这里是我正在使用的工件坐标。

apply plugin: 'java'
apply plugin: 'application'
mainClassName = "SortPerfMain"

dependencies {
compile "net.java.dev.glazedlists:glazedlists_java15:1.8.0"
compile "org.swinglabs.swingx:swingx-core:1.6.4"
}

这里是例子。我尝试使用 EventList 的唯一原因是因为我想要一个数据结构,我可以在 TableModel 之外修改它并发出必要的通知。

    import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.gui.TableFormat;
import ca.odell.glazedlists.swing.EventTableModel;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.renderer.*;
import org.jdesktop.swingx.table.TableColumnExt;

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;

import static javax.swing.WindowConstants.EXIT_ON_CLOSE;

/* This class creates a JFrame with two JXTables displayed side by side. Both
* tables have a single column that holds Item objects. Each Item has one
* property; amount. The amount property is a BigDecimal, but the performance
* disparity is still present when using int instead.
*
* The first table is backed by a simple ArrayList. The second table is backed
* by an EventList (GlazedLists).
*
* When sorting 1,000,000 rows, the first table takes about 1 second and the
* second table takes about 10 seconds.
*/

public class SortPerfMain {
@SuppressWarnings("FieldCanBeLocal")
private final boolean useDebugRenderer = true;

// The number of items that should be added to the model.
@SuppressWarnings("FieldCanBeLocal")
private final int itemCount = 2;

// The number of visible rows in each table.
@SuppressWarnings("FieldCanBeLocal")
private final int visibleRowCount = 2;

public static void main(String[] args) {
new SortPerfMain();
}

public SortPerfMain() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
List<Item> itemList = createItemList();

JPanel leftPanel = createTablePanel(
createTable(createSimpleModel(itemList)));

JPanel rightPanel = createTablePanel(
createTable(createGlazedModel(itemList)));

JPanel mainPanel = new JPanel(new GridLayout(1, 2));
mainPanel.add(leftPanel);
mainPanel.add(rightPanel);

JFrame mainFrame = new JFrame("Table Sort Perf");
mainFrame.setContentPane(mainPanel);
mainFrame.pack();
mainFrame.setSize(600, mainFrame.getHeight());
mainFrame.setLocationRelativeTo(null);
mainFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
mainFrame.setVisible(true);
}
});
}

private List<Item> createItemList() {
List<Item> itemList = new ArrayList<>(itemCount);
for (int i = 0; i < itemCount; i++) {
itemList.add(new Item(i));
}
return itemList;
}

private JXTable createTable(TableModel model) {
JXTable table = new JXTable(model);
table.setVisibleRowCount(visibleRowCount);
addRenderer(table);
return table;
}

private void addRenderer(JXTable table) {
TableColumnExt column = table.getColumnExt(Columns.AMOUNT.ordinal());
column.setCellRenderer(createCurrencyRenderer());
}

private JPanel createTablePanel(JXTable table) {
JLabel panelLabel = new JLabel(table.getModel().getClass().getName());
JPanel panel = new JPanel(new BorderLayout());

panel.add(panelLabel, BorderLayout.NORTH);
panel.add(new JScrollPane(table), BorderLayout.CENTER);

return panel;
}

private TableModel createSimpleModel(List<Item> items) {
return new SimpleTableModel(items);
}

private TableModel createGlazedModel(List<Item> items) {
EventList<Item> itemList = new BasicEventList<>();
itemList.addAll(items);
return new EventTableModel<>(itemList, new EventTableModelFormat());
}

private TableCellRenderer createCurrencyRenderer() {
//noinspection ConstantConditions
if (useDebugRenderer) {
return new DebugRenderer();
}

return new DefaultTableRenderer(
new LabelProvider(new FormatStringValue(
NumberFormat.getCurrencyInstance())));
}

// Enum for managing table columns
private static enum Columns {
AMOUNT("Amount", BigDecimal.class);

private final String name;
private final Class type;

private Columns(String name, Class type) {
this.name = name;
this.type = type;
}
}

// Each table holds a list of items.
private static class Item {
private final BigDecimal amount;

private Item(BigDecimal amount) {
this.amount = amount;
}

private Item(int amount) {
this(new BigDecimal(amount));
}
}

// A simple model that doesn't perform any change notification
private static class SimpleTableModel extends DefaultTableModel {
private final List<Item> itemList;

public SimpleTableModel(List<Item> items) {
this.itemList = items;
}

@Override
public int getRowCount() {
if (itemList == null) {
return 0;
}

return itemList.size();
}

@Override
public int getColumnCount() {
return Columns.values().length;
}

@Override
public Object getValueAt(int rowIndex, int columnIndex) {
switch (Columns.values()[columnIndex]) {
case AMOUNT:
return itemList.get(rowIndex).amount;
}

return null;
}

@Override
public String getColumnName(int column) {
return Columns.values()[column].name;
}

@Override
public Class<?> getColumnClass(int column) {
return Columns.values()[column].type;
}
}

// Table format for use with the EventTableModel
private static class EventTableModelFormat implements TableFormat<Item> {
@Override
public int getColumnCount() {
return 1;
}

@Override
public String getColumnName(int i) {
return Columns.values()[i].name;
}

@Override
public Object getColumnValue(Item item, int i) {
return item.amount;
}
}

/* The following classes are used to add println statements to the part
* of the component hierarchy we're interested in for debugging.
*/

private class DebugRenderer extends DefaultTableRenderer {
private DebugRenderer() {
super(new DebugProvider());
}

@Override
public Component getTableCellRendererComponent(
JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
System.out.println("Renderer requested for " + value.toString());
return super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, column);
}
}

private class DebugProvider extends LabelProvider {
private DebugProvider() {
super(new DebugFormatter());
}

@Override
public String getString(Object value) {
System.out.println("Providing string for " + value.toString());
return super.getString(value);
}
}

private class DebugFormatter extends FormatStringValue {
private DebugFormatter() {
super(NumberFormat.getCurrencyInstance());
}

@Override
public String getString(Object value) {
System.out.println("Formatting object: " + value.toString());
return super.getString(value);
}
}
}

我还注意到 EventTableModel 支持的表是根据字符串值而不是数值排序的,但我不确定为什么。以下是来自分析器的几个屏幕截图,其中有一百万行正在排序。

First Table

Second Table

有什么想法吗?

最佳答案

我遇到的问题是 SwingX 的 TableRowSorterModelWrapper 与 GlazedLists 的 TableFormat 结合使用的方式。

当使用 GlazedLists 的 TableFormat 时,不为表列提供类类型。如果未提供类类型,JXTable 将最终根据 ComponentProvider 提供的字符串值对列进行排序。如果 ComponentProvider 是使用 FormatStringValue 转换器构造的,则列中的每个项目都将在排序期间用于比较之前进行格式化。对 ComponentProvider 的实际调用发生在 TableRowSorterModelWrapper 中。

在我的例子中,当我添加自定义渲染器时,我将默认的 ComponentProvider 替换为使用 FormatStringValueLabelProvider使用从 NumberFormat.getCurrencyInstance() 返回的格式化程序。

使用我的 SimpleTableModel 的表没有遇到同样的性能问题是因为它提供了列类类型。由于 BigDecimal 实现了 Comparable,排序操作不需要调用 ComponentProvider 来获取(可能格式化的)字符串值。

解决方法很简单;使用 GlazedLists 的 AdvancedTableFormat 而不是 TableFormat 并为每个表列提供类类型。以下将与我的问题中的示例一起使用。

private static class EventTableModelFormat implements AdvancedTableFormat<Item> {
@Override
public int getColumnCount() {
return 1;
}

@Override
public String getColumnName(int i) {
return Columns.values()[i].name;
}

@Override
public Object getColumnValue(Item item, int i) {
return item.amount;
}

@Override
public Class getColumnClass(int column) {
return Columns.values()[column].type;
}

@Override
public Comparator getColumnComparator(int column) {
return null;
}
}

关于java - 当我切换到 GlazedLists 的 EventTableModel 时,为什么我的 JXTable 排序如此之慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12329281/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com