0

When I try to load the data from the textfile, with data like this

java;sdf;2.0;3.0;
cpp;sdks;24.6;89.0;

I'm getting the NoSuchElementException with this code.

public void loadFile() {
  Scanner scan = null;  
  int n = 0;
  try {
     scan = new Scanner(new File(this.filename)).useDelimiter(";");
     this.items.clear();
     
     while (scan.hasNextLine()) {
        String name = scan.next();
        String barcode = scan.next();
        double unitPrice = scan.nextDouble();
        double shipCost = scan.nextDouble();

        Product newProduct = new Product(name, barcode, unitPrice, shipCost);
        this.items.add(newProduct);
        n++;
     }
  } 
  catch (IOException e) {
     System.err.println("Caught IOException: " + e.getMessage());
  } catch (InputMismatchException e) {
     System.err.println("Caught InputMismatchException: " + e.getMessage());
     System.out.println(n + " products loaded!");
  } catch (NoSuchElementException e) {
     System.err.println("Attempt to read past end of file");
  } catch (IllegalStateException e) {
     System.err.println("Attempt to read a closed file");
  } finally {
     if (scan != null)
        scan.close();
  }
}
Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46
  • Does this answer your question? [No Such Element Exception?](https://stackoverflow.com/questions/8032099/no-such-element-exception) – Martin Zeitler Mar 20 '22 at 19:43

2 Answers2

0

hasNextLine() method waits unitl there is no nextLine but hasNext() waits until there is next token

For solution perspective use :

 while (scan.hasNext()) {
            String name = scan.next();
            String barcode = scan.next();
            double unitPrice = scan.nextDouble();
            double shipCost = scan.nextDouble();

            System.out.println(name);

            n++;
         }

This will solve your problem

0

There are several approaches how you can solve this.

1. Advance to the next line when all token on the current line have been read.

For that, add the line scan.nextLine() at the end of the loop. Method nextLine() will return the whole current line (that value will be omitted) and will set the scanners position at the beginning of the next line.

while (scan.hasNextLine()) {
    // reading tokens and creating new Product

    scan.nextLine();
}

2. Change the condition in the while loop to scan.hasNext(). So that it'll check whether more token exists.

But another problem will arise: stating from the second item all item names will contain a new line character (\n) at the beginning.

To handle it, you can either apply strip() on a name, change the delimiter to "[;\\r\\n]+" (with that every new line character \nand carriage return\r` character as well as semicolon will be omitted.

can = new Scanner(new File(this.filename)).useDelimiter("[;\\r\\n]+");
this.items.clear();
            
while (scan.hasNext()) {
    // code inside the loop remains the same
}

The drawback of this approach: condition scan.hasNext() that check existence of a single token doesn't clearly show the intention to read the line comprised of four tokens.

3. The last option is to read the file line by line with scan.nextLine() and then apply split(";") on it, which will give an array of strings.

This solution might look a bit more tedious because it'll require to handle the splitting to parse double values manually.

while (scan.hasNextLine()) {
    String[] line = scan.nextLine().split(";");
    String name = line[0];
    String barcode = line[1];
    double unitPrice = Double.parseDouble(line[2]);
    double shipCost = Double.parseDouble(line[3]);

    Product newProduct = new Product(name, barcode, unitPrice, shipCost);
    this.items.add(newProduct);
}

All solutions above are tested with the provided file-example and a dummy Product class.

Output (items list contents)

[Product{name='java', barcode='sdf', unitPrice=2.0, shipCost=3.0}, Product{name='cpp', barcode='sdks', unitPrice=24.6, shipCost=89.0}]
Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46