Problem inputting values from CSV file into ArrayList

75 Views Asked by At

I am trying to build a terminal mode application that allows a user to input certain attributes as a filtered search of Toyota vehicles released in the 80s. This is an assignment for a class so there are restrictions like having the original data in a CSV file and the data must be loaded into an ArrayList of objects (Toyota vehicles in my case). I decided to use a BufferedReader to read the data and set the values from the CSV file as arguments for instantiating new vehicles and adding them to the ArrayList.

Here is the method implementing what I just explained:

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));
        }

    } 

My ToyotaVehicle class:

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;
    }

}

When I run the code, I get this error message:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 at data.LoadData.load(LoadData.java:28) at Driver.main(Driver.java:7)

I apologize in advance if I seem to be missing an obvious mistake here. The only thing I've tried is at first I used the files[] array values as direct arguments rather than setting variables for each array value, no luck. I've read up on most forums/posts relating to this same issue and have yet to find a solution. I've used BufferedReader a handful of times before and have never ran into this problem. Any help would be appreciated, thanks.

2

There are 2 best solutions below

0
rzwitserloot On

There's a blank line in the input file. Possibly at the end. This results in the result of .split(",") to be a zero-length array, thus resulting in an ArrayIndexOutOfBoundsException when trying fields[0]. Trivially by checking for this in your loop:

while((line = br.readLine()) != null) {
  if (line.isEmpty()) continue; // add this
  String[] fields = line.split(",");
  int modelYear = Integer.parseInt(fields[0]);
  ....
}
5
Reilas On

"... When I run the code, I get this error message: ..."

The ArrayIndexOutOfBoundsException class is thrown when an array is accessed with an invalid index.
For example, if you had 5 values and tried to access the 6th.

According to the error, it was thrown from the load method.
The only array in load, is fields, so this means that one of the CSV lines is not formatted correctly.

Here is a way to resolve the error.

First, use a −1 limit parameter, with the split method.
This will preserve trailing commas as empty values, e.g., "1,2,3,,,".

String[] fields = line.split(",", -1);

Skip over any line that does not have 6 elements.
Additionally, create a List to hold the ill-formatted lines for debugging.

List<String> list = new ArrayList<>();
String[] fields = line.split(",", -1);
if (fields.length != 6) {
    list.add(line);
    continue;
}

Here is the re-factor.

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));
    }

}

Here are a some additional un-related recommendations.

Optionally, just use "src/files/80stoyota.csv".
The File class infers a relative path.

Use the Scanner class, instead of BufferedReader.

try(Scanner in = new Scanner(new File("src/files/80stoyota.csv")))

And, use a record class instead of a class.

record ToyotaVehicle(int y, String n, String c, String e, boolean s, String f) { }

Here is an additional re-factor.

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);

}

Edit

"... I have commas included in data so it's splitting it and creating more fields than there should be. I tried using double quotes around fields that contain a comma but no luck. ..."

There are a few ways to resolve this.

If you had created the CSV file, just use a different delimiter other than a comma.
A comma is not required.
Wikipedia – Delimiter-separated values.

If not, try parsing with a regular expression pattern.
Here is a relevant question and answer.
StackOverflow – Java: splitting a comma-separated string but ignoring commas in quotes.

Or, utilize a third-party library, I've heard that Apache Commons works well for this.
Apache Commons – CSV.