0

I'm in the process of creating a program that reads data from an external file, compares it with other data within the file then prints the results to a new external file. I am having problems with the while loop section of my code. I am unsure whether it is the while loop itself or the for loop which is nested within. Here is the code:

public class WageCalculator {

  public static void main(String[] args) throws FileNotFoundException {

    Scanner input = new Scanner(new FileReader("TestData.txt")); //Scanner for external file
    PrintWriter output = new PrintWriter("wagedaily.txt");

    float RecommendedMaximum;
    RecommendedMaximum = Float.parseFloat(JOptionPane.showInputDialog(null, "Enter the recommended maximum journey cost:"));

    String ShipID, JourneyID; //Variables
    int JourneyLength, Crew;
    double RateOfPay, CrewCost, TotalCost;

    while (input.hasNext()) { //EOF-Controlled While Loop
      ShipID = input.nextLine();
      JourneyID = input.nextLine();
      JourneyLength = input.nextInt();
      Crew = input.nextInt();

      CrewCost = 0; //Default Values Set
      TotalCost = 0;
      for (int x = Crew; x > 0; x--) { //For Loop updates the above values
        RateOfPay = input.nextDouble();
        CrewCost = RateOfPay * JourneyLength;
        TotalCost = TotalCost + CrewCost;
      }

      if (TotalCost < RecommendedMaximum) { //if-else statements to compare values
        System.out.println("The total cost of...");
        output.println("The total cost of...");
      } else if (TotalCost == RecommendedMaximum) {
        System.out.println("The total cost of...");
        output.println("The total cost of...");
      } else {
        System.out.println("The total cost of...");
      }
    }

    output.close(); //Close both Scanner and Printwriter
    input.close();
  }

}

The error I get is this:

Exception in thread "main" java.util.InputMismatchException  
at java.util.Scanner.throwFor(Unknown Source)  
at java.util.Scanner.next(Unknown Source)  
at java.util.Scanner.nextInt(Unknown Source)  
at java.util.Scanner.nextInt(Unknown Source)  
at (package).WageCalculator.main(WageCalculator.java:30)

The error says it's line 30 in my code that is the problem but I am not so sure.

Incase anyone needs to see the TestData.txt file:

Monarch  //ShipID
M141     //JourneyID
16       //JourneyLength
6        //Crew
10.5     //RateOfPay -
10.5
20
20
20
30       //- RateOfPay
Princess //ShipID
P103     //JourneyID
18       //JourneyLength
5        //Crew
40       //RateOfPay -
45
45
60
80       //- RateOfPay

Any help would be appreciated :)

Nathan Farren
  • 23
  • 1
  • 7

2 Answers2

4

You're making a bunch of input.nextXXX() calls within the loop after checking input.hasNext() only once at the top of the loop. Don't do that as this is very unsafe and bound to fail and as there should always be a one-to-one correspondence between a check and a get. For instance, if you want to get a next line, there should be one input.HasNextLine() called before calling calling input.nextLine(). Same for input.next() or input.nextInt().

Myself, I'd read line by line by checking hasNextLine() and then once reading in the nextLine(), and then manipulating the String received.

while (input.hasNextLine()) {
   String line = input.nextLine();

   // now do not use input further within the loop
}

You could then within the loop use a second Scanner using the line received, or split the line via String#split(String regex) or do whatever you need to do with it.

Or you could use String replaceAll(...) and regular expressions to get rid of all white space followed by "//" followed by any chars. e.g.,

  while (input.hasNextLine()) {
     String line = input.nextLine();

     // get rid of white space followed by "//" followed by anything
     line = line.replaceAll("\\s+//.*", "");
     System.out.println(line);
  }

Edit
I've looked a bit more into your question and your data, and I am going to amend my answer. If you're absolutely sure of the integrity of your data file, you could consider checking for nextline once per obtaining data of an entire ship. For example:

public static void main(String[] args) {
  InputStream inStream = GetData.class.getResourceAsStream(DATA_FILE);
  List<Cruise> cruiseList = new ArrayList<>();
  Scanner input = new Scanner(inStream);
  while (input.hasNext()) {
     String name = getLine(input);
     String id = getLine(input);
     int length = Integer.parseInt(getLine(input));
     int crew  = Integer.parseInt(getLine(input));

     // assuming a class called Cruise
     Cruise cruise = new Cruise(name, id, length, crew);

     for (int i = 0; i < crew; i++) {
        cruise.addPayRate(Double.parseDouble(getLine(input)));
     }

     cruiseList.add(cruise);
  }

  input.close();
}

private static String getLine(Scanner input) {
  String line = input.nextLine();

  // get rid of white space followed by "//" followed by anything
  line = line.replaceAll("\\s+//.*", "");
  return line;
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • An easier way to modify the existing code would be to write functions as aliases of nextLine() and nextInt() with checks included; they could throw an exception to pull you out of the existing loop. – Matt Rollins Jan 08 '15 at 16:30
  • 1
    @Matt Surely `nextLine()` and `nextInt()` already throw exceptions if they run out of data. – khelwood Jan 08 '15 at 16:33
  • @khelwood True, that's a silly oversight of mine. After all, the initial problem was that those exceptions weren't being caught. Actually, the particular exception that was thrown makes it look like he has those comments actually in his file, or something is out of order. – Matt Rollins Jan 08 '15 at 18:06
2

The reason it gives you trouble is because when the user enters an integer then hits enter, two things have just been entered - the integer and a "newline" which is \n. The method you are calling, "nextInt", only reads in the integer, which leaves the newline in the input stream. But calling nextLine() does read in newlines, which is why you had to call nextLine() before your code would work. You could have also called next(), which would also have read in the newline.

Also read the Documentation of Scanner class for further understanding :

Here is the Corrected Code :

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.Scanner;

import javax.swing.JOptionPane;

public class WageCalculator {

      public static void main(String[] args) throws FileNotFoundException {

        Scanner input = new Scanner(new FileReader("TestData.txt")); //Scanner for external file
        PrintWriter output = new PrintWriter("wagedaily.txt");

        float RecommendedMaximum;
        RecommendedMaximum = Float.parseFloat(JOptionPane.showInputDialog(null, 
                                                "Enter the recommended maximum journey cost:"));

        String ShipID, JourneyID; //Variables
        int JourneyLength, Crew;
        double RateOfPay, CrewCost, TotalCost;

        while (input.hasNext()) { //EOF-Controlled While Loop
            System.out.println("While Enter"); // For debugging purpose
            ShipID = input.nextLine();
            JourneyID = input.nextLine();
            JourneyLength = input.nextInt();
            input.nextLine();     // Enter this to read the data of skipped Line
            Crew = input.nextInt();
            input.nextLine();
            CrewCost = 0; //Default Values Set
            TotalCost = 0;
            for (int x = Crew; x > 0; x--) { //For Loop updates the above values
                System.out.println("While Under if Enter");// For debugging purpose
                RateOfPay = input.nextDouble();
                input.nextLine();
                CrewCost = RateOfPay * JourneyLength;
                TotalCost = TotalCost + CrewCost;
                System.out.println("While Under if Exit");// For debugging purpose
            }

            if (TotalCost < RecommendedMaximum) { //if-else statements to compare values
                output.println("The total cost of...");
            } else if (TotalCost == RecommendedMaximum) {
                System.out.println("The total cost of...");
                output.println("The total cost of...");
            } else {
                System.out.println("The total cost of...");
            }
            System.out.println("While Exit"); // For debugging purpose
        }    
        output.close(); //Close both Scanner and Printwriter
        input.close();
    }

}
Amitesh Rai
  • 866
  • 11
  • 21