我想检查一个Excel .csv列,它可以是String,Int oder Double类型。我实现了一个经典的通用Pair类:
public class PairT<K,V> implements Comparable<PairT<K,V>>
如果是整数列,则列值存储在:
中ArrayList<PairT<Integer,Integer>> column_list = new ArrayList<>();
其中V
值包含excel行索引。
下面的代码片段显示了令人讨厌的解决方案 - 我会改进:
// Add a cell value of type T to the column list
@SuppressWarnings("unchecked")
public static <T> void addCell(
String excelcell,
int row_idx,
boolean ignorecase,
T defkey,
/*IO*/ArrayList<PairT<T,Integer>> column_list) throws RuntimeException
{
//Class<?> classtype = defkey.getClass(); String typename = classtype.getSimpleName();
char type;
if (defkey instanceof String) type = 'S';
else if (defkey instanceof Integer) type = 'I';
else if (defkey instanceof Double) type = 'D';
else type = 'O'; // other
T key;
try
{
switch(type)
{
case 'I':
try
{ key = (T)new Integer(excelcell);
} catch (NumberFormatException e) { key = defkey; }
column_list.add(new PairT<T,Integer>(key,row_idx));
break;
case 'D':
try
{ key = (T)new Double(excelcell);
} catch (NumberFormatException e) { key = defkey; }
column_list.add(new PairT<T,Integer>(key,row_idx));
break;
case 'S':
if (ignorecase) excelcell = excelcell.toUpperCase();
column_list.add(new PairT<T,Integer>((T)excelcell,row_idx));
break;
default: // Other take the .toString() output as key
column_list.add(new PairT<T,Integer>((T)excelcell.toString(),row_idx));
}
}catch (Exception ex) // possibly a ClassCastException
{
throw new RuntimeException("addCell(): Problems using PairT<K,V>",ex);
}
} //----- end of addCell()
测试我使用:
ArrayList<PairT<Integer,Integer>> column_list = new ArrayList<>();
int row_idx = 0;
boolean ic = true; // for String values only;
Integer defval = new Integer("0");
String cell = "12";
addCell(cell,row_idx,ic,defval,column_list);
cell = "17.34"; // leads to def val
addCell(cell,++row_idx,ic,defval,column_list);
cell = "456";
addCell(cell,++row_idx,ic,defval,column_list);
cell = "foo"; // lead to def avlue
addCell(cell,++row_idx,ic,defval,column_list);
System.out.println("result: " + column_list);
// [12;0, 0;1, 456;2, 0;3]
java.util.Collections.sort(column_list);
System.out.println("Sorted: " + column_list);
//Sorted: [0;1, 0;3, 12;0, 456;2]
它按预期工作,但是 - 我说 - 我不想区分addCell()中的Type T. 我更喜欢简短的解决方案,例如:
if (ignorecase) column_list.add(new PairT<T,Integer>((T)excelcell.toUpperCase(),row_idx));
else column_list.add(new PairT<T,Integer>((T)excelcell,row_idx));
答案 0 :(得分:1)
您的代码中存在一些问题;
首先,您将column_list
定义为Integer
值对的列表。您希望将其定义为ArrayList<PairT<T, Integer>> column_list = new ArrayList<>();
,以允许存储String,Double或Integer数据。
其次,在addCell()
中,检查整数defval
的类型,它的值始终为0.然后在以下switch语句中使用从此变量推断的类型,这意味着您执行Integer
的代码,无论excelCell
的类型是什么。
考虑到这些因素,我使用泛型类型参数清理了代码addCell()
。
public class Main {
@SuppressWarnings("unchecked")
public static <T> void main(String[] args) {
ArrayList<PairT<T, Integer>> list = new ArrayList<>();
int row_idx = 0;
String cell = "12";
addCell((T)cell, row_idx, list);
cell = "17.34";
addCell((T)cell, ++row_idx, list);
cell = "456";
addCell((T)cell, ++row_idx, list);
cell = "foo";
addCell((T)cell, ++row_idx, list);
System.out.println("result: " + list);
java.util.Collections.sort(list);
System.out.println("Sorted: " + list);
}
@SuppressWarnings("unchecked")
public static <T> void addCell(T excelCell, int row_idx, ArrayList<PairT<T, Integer>> list){
if(excelCell instanceof String) list.add((PairT<T, Integer>) new PairT<>(((String) excelCell).toUpperCase(), row_idx));
else list.add(new PairT<>(excelCell, row_idx));
}
我已移除ignoreCase
和defval
,因为它们与此示例无关。
答案 1 :(得分:0)
您可以使用我在my answer here中描述的内容并将Class<T>
映射到Function<String, T>
,但我倾向于同意VGR的评论,即您应该重新考虑使用方式仿制药在这里。
重构代码的一种简单方法,我认为VGR建议,就像这样:
public static void addCell
(String excelCell,
int rowIdx,
boolean ignoreCase,
Integer defCellValue,
List<PairT<Integer, Integer>> columnList)
{
Integer cellValue;
try {
cellValue = Integer.valueOf(excelCell);
} catch (NumberFormatException x) {
cellValue = defCellValue;
}
columnList.add(new PairT<>(cellValue, rowIdx));
}
// addCell overload with Double defCellValue
// addCell overload with String defCellValue
你可以一般化并做一些这样的事情,虽然如果你只有几个重载它不会那么多:
public static void addCell
(String excelCell,
int rowIdx,
boolean ignoreCase,
Integer defCellValue,
List<PairT<Integer, Integer>> columnList)
{
addCell(excellCell,
rowIdx,
ignoreCase,
defCellValue,
columnList,
Integer::valueOf);
}
public static void addCell(..., Double defCellValue, ...) {
addCell(..., Double::valueOf);
}
public static void addCell(..., String defCellValue, ...) {
addCell(..., Function.identity());
}
private static <T> void addCell
(String excelCell,
int rowIdx,
boolean ignoreCase,
T defCellValue,
List<PairT<T, Integer>> columnList,
Function<String, T> cellParser)
{
if (ignoreCase) {
excelCell = excelCell.toUpperCase();
}
T cellValue;
try {
cellValue = cellParser.apply(excelCell);
} catch (IllegalArgumentException x) {
cellValue = defValue;
}
columnList.add(new PairT<>(cellValue, rowIdx));
}
其他一些事情:
写下例如更有意义一个class Cell<T> { int row, col; T value; }
而不是尝试使用一对类。对类非常嘈杂,难以使用,你不能在对类中编写特定于单元格的实用方法。
您应该坚持使用Java命名约定。静态常量为大写,空格为下划线(static final int FOO_COUNT;
),所有其他变量均为驼峰式,第一个字母为小写(int fooCount;
)。