如果至少有一个值(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
原语是boxed如Double
,生成具有 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/