提问人:herb 提问时间:10/16/2023 最后编辑:herb 更新时间:10/17/2023 访问量:67
将 CSV 文件中的值输入到 ArrayList 时出现问题
Problem inputting values from CSV file into ArrayList
问:
我正在尝试构建一个终端模式应用程序,允许用户输入某些属性作为 80 年代发布的丰田汽车的过滤搜索。这是一个类的作业,因此存在一些限制,例如将原始数据放在 CSV 文件中,并且必须将数据加载到对象的 ArrayList 中(在我的情况下是丰田汽车)。我决定使用 BufferedReader 来读取数据,并将 CSV 文件中的值设置为实例化新车辆并将它们添加到 ArrayList 的参数。
以下是实现我刚才解释的方法:
public void load() {
toyotaVehicleCatalog = new ArrayList<>();
try(BufferedReader br = new BufferedReader(new FileReader("./src/files/80stoyota.csv"))) {
String line = "";
while((line = br.readLine()) != null) {
String[] fields = line.split(",");
int modelYear = Integer.parseInt(fields[0]); //Line 28
String modelName = fields[1];
String modelCode = fields[2];
String modelEngine = fields[3];
boolean sedan = fields[4].length() > 0 ? true : false;
String funFact = fields[5];
ToyotaVehicle vehicle = new ToyotaVehicle(modelYear, modelName, modelCode, modelEngine, sedan, funFact);
toyotaVehicleCatalog.add(vehicle);
}
} catch(IOException ex) {
ex.printStackTrace();
}
for(int i = 0; i < toyotaVehicleCatalog.size(); i++) {
System.out.println(toyotaVehicleCatalog.get(i));
}
}
我的丰田车辆类:
public class ToyotaVehicle {
private String modelCode;
private int modelYear;
private String modelName;
private String engine;
private boolean sedan;
private String funFact;
public ToyotaVehicle(int modelYear, String modelName, String modelCode, String engine, boolean sedan, String funFact) {
this.modelCode = modelCode;
this.modelYear = modelYear;
this.modelName = modelName;
this.engine = engine;
this.sedan = sedan;
this.funFact = funFact;
}
public ToyotaVehicle() {
}
public String getModelCode() {
return modelCode;
}
public void setModelCode(String modelCode) {
this.modelCode = modelCode;
}
public int getModelYear() {
return modelYear;
}
public void setModelYear(int modelYear) {
this.modelYear = modelYear;
}
public String getModelName() {
return modelName;
}
public void setModelName(String modelName) {
this.modelName = modelName;
}
public String getEngine() {
return engine;
}
public void setEngine(String engine) {
this.engine = engine;
}
public boolean isSedan() {
return sedan;
}
public void setSedan(boolean sedan) {
this.sedan = sedan;
}
public String getFunFact() {
return funFact;
}
public void setFunFact(String funFact) {
this.funFact = funFact;
}
}
当我运行代码时,我收到以下错误消息:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 at data.LoadData.load(LoadData.java:28) at Driver.main(Driver.java:7)
如果我在这里似乎遗漏了一个明显的错误,我提前道歉。我唯一尝试过的是,起初我使用数组值作为直接参数,而不是为每个数组值设置变量,没有运气。我已经阅读了与同一问题相关的大多数论坛/帖子,但尚未找到解决方案。我以前使用过几次 BufferedReader,但从未遇到过这个问题。任何帮助将不胜感激,谢谢。files[]
答:
输入文件中有一个空行。可能在最后。这导致结果为零长度数组,从而在尝试时产生 .微不足道
通过在循环中检查这一点:.split(",")
ArrayIndexOutOfBoundsException
fields[0]
while((line = br.readLine()) != null) {
if (line.isEmpty()) continue; // add this
String[] fields = line.split(",");
int modelYear = Integer.parseInt(fields[0]);
....
}
"...当我运行代码时,我收到以下错误消息:...”
当使用无效索引访问数组时,将引发 ArrayIndexOutOfBoundsException 类。
例如,如果您有 5 个值并尝试访问第 6 个值。
根据错误,它是从 load 方法抛出的。
加载中唯一的数组是字段,因此这意味着其中一行 CSV 行的格式不正确。
这是解决该错误的方法。
首先,使用 −1 极限参数和 split 方法。
这会将尾随逗号保留为空值,例如“1,2,3,,,”。
String[] fields = line.split(",", -1);
跳过任何没有 6 个元素的行。
此外,创建一个 List 来保存格式不正确的行以进行调试。
List<String> list = new ArrayList<>();
String[] fields = line.split(",", -1);
if (fields.length != 6) {
list.add(line);
continue;
}
这是重构。
void load() {
toyotaVehicleCatalog = new ArrayList<>();
List<String> list = new ArrayList<>();
try(BufferedReader br = new BufferedReader(new FileReader("./src/files/80stoyota.csv"))) {
String line = "";
while((line = br.readLine()) != null) {
String[] fields = line.split(",", -1);
if (fields.length != 6) {
list.add(line);
continue;
}
int modelYear = Integer.parseInt(fields[0]);
String modelName = fields[1];
String modelCode = fields[2];
String modelEngine = fields[3];
boolean sedan = fields[4].length() > 0 ? true : false;
String funFact = fields[5];
ToyotaVehicle vehicle = new ToyotaVehicle(modelYear, modelName, modelCode, modelEngine, sedan, funFact);
toyotaVehicleCatalog.add(vehicle);
}
} catch(IOException ex) {
ex.printStackTrace();
}
list.forEach(System.out::println);
for(int i = 0; i < toyotaVehicleCatalog.size(); i++) {
System.out.println(toyotaVehicleCatalog.get(i));
}
}
以下是一些与此无关的其他建议。
或者,只需使用“src/files/80stoyota.csv”。
File 类推断相对路径。
使用 Scanner 类,而不是 BufferedReader。
try(Scanner in = new Scanner(new File("src/files/80stoyota.csv")))
并且,使用记录类而不是类。
record ToyotaVehicle(int y, String n, String c, String e, boolean s, String f) { }
这是一个额外的重因。
void load() {
toyotaVehicleCatalog = new ArrayList<>();
List<String> list = new ArrayList<>();
try(Scanner in = new Scanner("src/files/80stoyota.csv")) {
String line = "", f[];
while((line = in.nextLine()) != null) {
f = line.split(",", -1);
if (f.length != 6) {
list.add(line);
continue;
}
toyotaVehicleCatalog.add(
new ToyotaVehicle(Integer.parseInt(f[0]), f[1], f[2], f[3], !f[4].isEmpty(), f[5]));
}
}
list.forEach(System.out::println);
toyotaVehicleCatalog.forEach(System.out::println);
}
编辑
"...我在数据中包含逗号,因此它正在拆分它并创建比应有的字段更多的字段。我尝试在包含逗号的字段周围使用双引号,但没有运气。..."
有几种方法可以解决此问题。
如果您已创建 CSV 文件,只需使用逗号以外的其他分隔符即可。
不需要逗号。
Wikipedia – 分隔符分隔的值。
如果没有,请尝试使用正则表达式模式进行解析。
这是一个相关的问题和答案。
StackOverflow – Java:拆分逗号分隔的字符串,但忽略引号中的逗号。
或者,使用第三方库,我听说 Apache Commons 在这方面效果很好。
Apache Commons – CSV。
评论
fields[]
1984, Toyota 4Runner, N60, "2.4 L I4", N, "The N60 was the first generation for the 4Runner. Toyota essentially added a removable fiberglass top to a Toyota pick-up truck. This concept helped set the stage for future off-road SUVs pf its kind."
评论
public record ToyotaVehicle( int modelYear, String modelName, String modelCode, String engine, boolean sedan, String funFact ) {}