Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在我的情况下,避免使用幻数的最佳方法_Java_Architecture - Fatal编程技术网

Java 在我的情况下,避免使用幻数的最佳方法

Java 在我的情况下,避免使用幻数的最佳方法,java,architecture,Java,Architecture,我正在读取一个有许多列(22)的文件,我正在使用openCSV来读取该文件 每一行都表示为一个字符串数组nextLine[] 我必须处理/验证列,不想将它们称为数字(即nextLine[0]…nextLine[22]) 我更愿意将它们称为nextLine[COLUMN\u A]nextLine[COLUMN\u B]……等等。 我最初的方法是使用枚举创建一个单例 public enum Columns { INSTANCE; public int COLUMN_A = 0;

我正在读取一个有许多列(22)的文件,我正在使用openCSV来读取该文件

每一行都表示为一个字符串数组
nextLine[]

我必须处理/验证列,不想将它们称为数字(即
nextLine[0]
nextLine[22]

我更愿意将它们称为
nextLine[COLUMN\u A]nextLine[COLUMN\u B]……等等。

我最初的方法是使用枚举创建一个单例

public enum Columns {
    INSTANCE;
    public int COLUMN_A = 0;  
    ....
    public int COLUMN_X = 22; 
}
然后我可以将该数组称为:

nextLine[Columns.INSTANCE.COLUMN_A]
问题

这是最好的方法吗? 我只是怀疑,因为我有另一个模型类,它只是为所有列提供了getter/setter,现在创建另一个类(singleton)以将列表示为索引似乎是一项额外的工作

对于上面的例子,如果我有一个模型类

public class Columns {
  private String columnA;
  public Columns (String columnA) {
    this.columnA = columnA;
  } 
  public void setColumnA(String columnA) {
    this.columnA = columnA;
  }
  public String getColumnA() {
    return this.columnA;
  }
} 

我可以使用
nextLine[columnA]
而不是创建单例枚举类吗?

我建议使用
HashMap

在您的例子中,可以是
HashMap

然后你可以得到你的价值观,比如:

String[] valuesIAmInterested =  map.get(columnA);
更好的是,您可以真正使用对象
作为地图的键

HashMap<Column, String[]>   map;
HashMap;

顺便说一句,enum不是单一模式。单一模式是一种特定的软件设计模式,enum传统上不这么认为。至少可以说,您对枚举的使用很奇怪。如果要使用枚举引用特定列,只需执行以下操作:

public enum Column {
    public int index;

    A(0), B(1), C(2), D(3);

    public Column( int index ) {
        this.index = index;
    }
}
然后你就说:

String columnAValue = csv[row][Column.A.index]
这样做还允许您迭代所有列,如下所示:

for( Column column : Column.values ) {
    String column = csv[row][column.index];
}
使用您使用的模式无法做到这一点,这使得使用枚举不值得。如果要继续执行您正在执行的操作,只需在文件顶部将它们设置为常规常量:

public class CsvParser {
    public static final int COLUMN_A = 0;
    public static final int COLUMN_B = 1;
    public static final int COLUMN_C = 2;

}
这与您使用的枚举方法没有区别,只是更直接,不涉及定义另一个枚举

现在谈谈你的问题。这是最好的模式吗?以及它所依赖的所有架构类型问题。您是否正在构建一个必须对CSV的每一列进行特定验证的程序?可能列A是一个整数,必须用作整数,列B是一个字符串,列C是一个枚举,等等。或者,您必须将特定的逻辑附加到每一列,如果数据的格式始终是可预测的,则此模式是有意义的。如果您必须支持多种数据格式,但它们是固定的(即仅format1、format2、format3),那么您可以继续遵循此模式

但是,如果您必须读取任何类型的csv格式,但需要附加一些固定数量的解析和/或逻辑,那么您必须读入有关csv的一些元数据,以了解哪些列是数字、哪些是字符串等,并且可以通过查看元数据来附加您的逻辑。当然,这更为灵活,但定义元数据、读取元数据以及处理元数据并非易事。如果你不需要这个模型,就不要这样做。另一个模型工作量小得多,而且同样健壮


如果你从大局来看这件事。在第一个体系结构中,我们有元数据。这是我们在程序中创建的枚举或常量。因此,元数据被内置到程序中。在第二种样式中,我们将元数据从程序中移到外部表示中,这样就不会烘焙到程序中。用户可以在运行时更改元数据,而在第一个版本中,元数据是无法更改的。

对于22列,我希望您不会单独处理这些列,而是以图解方式处理。因此,我将完全避免使用索引,并且

for (String columnElement : nextLine) {
  // process columnElement
}
如果每一列都有单独的、特定的含义,那么数组(或列表或映射)也不是最好的设计。然后我宁愿使用枚举或类对每一行进行建模()。我不会为每一行编写(g,s)字母,而是使用多态性,以便枚举/类知道如何处理每一列。或者更好:为一行创建一个类,将处理委托给Column类型的对象,例如

class Line {
  List<Column> columns;

  public void processLine() {
    for (Column c: columns) {
      c.processColumn();
  }

}

class Column {
  public void processColumn() {
    ...
  }
}
类行{
列出列;
public void processLine(){
用于(c列:列){
c、 processColumn();
}
}
类列{
public void processColumn(){
...
}
}

再想一想,我想这就是你可以做的:

public class CsvParser {

    private File file;
    private boolean hasHeader = false;
    private Map<String,Integer> columnIndexes;
    private List<String[]> rows = new ArrayList<String[]>();

    public CsvParser( File file, boolean hasHeader ) throws IOException {
        this.file = file;
        this.hasHeader = hasHeader;
    }

    // use this to parse the header from the file
    private void parseColumns(LineNumberReader reader) {
        String line = reader.nextLine();
        if( line != null ) {
            String[] columns = line.split(",");
            setColumns( columns );
        }
    }

    // use this if there is no header in the data.
    public void setColumns( String[] columns ) {
        columnIndex = new HashMap<String,Integer>();
        for( int i = 0; i < columns.length; i++ ) columnIndexes.put( columns.trim(), i);
    }

    public void parse() throws IOException {
        LineNumberReader reader = new LineNumberReader( new FileReader( file ) );
        try {
           if( hasHeader ) parseColumns(reader);
           while( (line = reader.nextLine()) != null ) {
              rows.add( line.split(",") );
           }
        } finally {
           reader.close();
        }
    }

    public Collection<String> getColumns() {
       return columnIndexes.keys();
    }

    public int size() {
       return rows.size();
    }

    public int getInt( int row, String column ) {
       return Integer.parseInt(getString(row,column));
    }

    public String getString( int row, String column ) {
       return rows.get(row)[columnIndexes.get(column)];
    }

    public double getDouble( int row, String column ) {
       return Double.parseDouble(getString(row,column));
    }

    public float getFloat( int row, String column ) {
       return Float.parseFloat(getString(row,column));
    }
}
公共类CsvParser{
私有文件;
私有布尔hasHeader=false;
私有地图索引;
私有列表行=新的ArrayList();
公共CsvParser(文件,布尔哈希头)引发IOException{
this.file=文件;
this.hasHeader=hasHeader;
}
//使用此命令可以解析文件的头
专用列(行号读取器){
String line=reader.nextLine();
如果(行!=null){
String[]columns=line.split(“,”);
设置列(列);
}
}
//如果数据中没有标题,则使用此选项。
公共void setColumns(字符串[]列){
columnIndex=newHashMap();
对于(inti=0;i