java - RowFilter.NumberFilter : can't handle "mixed" concrete number types

标签 java swing numbers compare rowfilter

如果至少有一个值(RowFilter 中的值 == 值,条目中的值)是小数,则会发生这种情况。这是一个失败的测试:

@Test
public void testRowFilterNumberMixCore() {
    TestEntry entry = new TestEntry(1.2f);
    RowFilter filter = RowFilter.numberFilter(ComparisonType.AFTER, 1, 0);
    assertTrue(entry + "must be included " + filter, filter.include(entry));
}

输出为:

junit.framework.AssertionFailedError: 
[entry: 1.2] must be included [RowFilter: ComparisonType = AFTER, comparableValue: 1, comparableClass: class java.lang.Integer]

The reason is that NumberFilter falls back to comparing the numbers by their number.longValue() if they are not the same class (and by that comparable to each other)

Knowing that detail, the test failure is not astonishing (in hind-sight, would have never thought of that being an issue ;-) One level of defense is to make sure - in client code - that the numbers to compare are of the same class. That's not always possible (think f.i.: a tableColumn with columnClass Number) So I'm wondering if/how to improve on the fallback. Something like:

if (one instanceof Comparable && one.getClass() == other.getClass()) {
    // same class, use comparator
    return ((Comparable) one).compareTo(other);
}
if (areIntegers(one, other)) {
    // all integers, use longValue
    return longCompare(one, other);
}
if (areDecimals(one, other)) {
    // anything to do here?
}
// at last resort convert to BigDecimal and compare those: 
BigDecimal bigOne = new BigDecimal(one.toString());
BigDecimal bigOther = new BigDecimal(other.toString());
return bigOne.compareTo(bigOther);

这样做可以使测试通过 - 我对隐藏的(阅读:我不知道:)陷阱有点警惕。非常欢迎任何警告/替代方案!

仅供引用:交叉发布到 OTN's Swing forum

后续

按照上面概述的方式实现,现在等待客户投诉 - 在这种情况下,我们会指责所有没有在这里警告我的人:-)

最佳答案

我没有更好的答案,但下面的例子说明了效果。特别是 RowFilter基于double原语是boxedDouble ,生成具有 values > 1 的预期画面 。相比之下,基于 float 的一个装箱为 Float 。由于类文字不匹配,include()比较 long值,意外地过滤了所有小数 values < 2 .

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.RowFilter;
import javax.swing.RowFilter.ComparisonType;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;

/** @see http://stackoverflow.com/questions/7993546 */
public class FilterTest {

    private static TableRowSorter<TableModel> sorter;
    private static RowFilter<TableModel, Integer> dFilter;
    private static RowFilter<TableModel, Integer> fFilter;
    private static boolean b;

    public static void main(String[] args) {
        TableModel model = new TableModel();
        JTable table = new JTable(model);
        sorter = new TableRowSorter<TableModel>(model);
        dFilter = RowFilter.numberFilter(ComparisonType.AFTER, 1d, 0);
        fFilter = RowFilter.numberFilter(ComparisonType.AFTER, 1f, 0);
        sorter.setRowFilter(dFilter);
        table.setRowSorter(sorter);
        JScrollPane scrollPane = new JScrollPane(table);
        table.setPreferredScrollableViewportSize(new Dimension(320, 240));

        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(scrollPane, BorderLayout.CENTER);
        f.add(new JToggleButton(new AbstractAction("Toggle") {

            @Override
            public void actionPerformed(ActionEvent e) {
                b = !b;
                if (b) {
                    sorter.setRowFilter(fFilter);
                } else {
                    sorter.setRowFilter(dFilter);
                }
            }
        }), BorderLayout.SOUTH);

        f.pack();
        f.setVisible(true);
    }

    private static class TableModel extends AbstractTableModel {

        private static final int ROWS = 16;
        private static final int COLS = 4;
        private Double[][] matrix = new Double[ROWS][COLS];

        public TableModel() {
            double v = 0;
            for (Object[] row : matrix) {
                Arrays.fill(row, Double.valueOf(v += 0.25));
            }
        }

        @Override
        public int getRowCount() {
            return ROWS;
        }

        @Override
        public int getColumnCount() {
            return COLS;
        }

        @Override
        public Object getValueAt(int row, int col) {
            return matrix[row][col];
        }

        @Override
        public Class<?> getColumnClass(int col) {
            return Number.class;
        }
    }
}

关于java - RowFilter.NumberFilter : can't handle "mixed" concrete number types,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7993546/

相关文章:

JavaFX、MouseEvent问题

java - hibernate 与资源利用

java - JComponent 未显示在 JPanel 上

java - 在进入循环之前显示 GlassPane

javascript - 通过数字动画化 CSS 属性

c++ - 如何编写一个快速函数来计算一个数的总除数?

java - 如何使用 Java 中的 SIGAR 或 OSHI API 获取特定应用程序的操作系统进程详细信息?

java - 使用 Hibernate 进行测试 : Object dependence chain on persistence

java - 更新标签内的变量

c++ - C++ 中的 "5.0f"和 "5.f"有什么区别?