【问题标题】:While loop with hasNext(); not fully looping带有 hasNext() 的 while 循环;没有完全循环
【发布时间】:2026-02-02 06:55:01
【问题描述】:

我正在创建一个程序,该程序从外部文件读取数据,将其与文件中的其他数据进行比较,然后将结果打印到新的外部文件中。我的代码的 while 循环部分有问题。我不确定是while循环本身还是嵌套在其中的for循环。代码如下:

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

}

我得到的错误是这样的:

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)

错误表明问题出在我的代码中的第 30 行,但我不太确定。

如果有人需要查看 TestData.txt 文件:

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

任何帮助将不胜感激:)

【问题讨论】:

  • 请在第 30 行所在的代码中添加注释。

标签: java for-loop while-loop eof


【解决方案1】:

在循环顶部仅一次检查input.hasNext() 之后,您在循环内进行了一堆input.nextXXX() 调用。不要这样做,因为这是非常不安全且必然会失败,并且 checkget 之间应该始终存在一对一的对应关系。例如,如果您想获得下一行,则应该在调用 input.nextLine() 之前调用一个 input.HasNextLine()input.next()input.nextInt() 相同。

我自己,我会逐行阅读,检查hasNextLine(),然后一次读入nextLine(),然后处理收到的字符串。

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

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

然后,您可以在循环中使用接收到的线路使用第二个 Scanner,或者通过 String#split(String regex) 拆分线路,或者做任何您需要做的事情。

或者您可以使用字符串replaceAll(...) 和正则表达式来删除所有空格,然后是“//”,然后是任何字符。例如,

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

编辑
我对您的问题和数据进行了更多研究,我将修改我的答案。 如果您完全确定数据文件的完整性,您可以考虑在获取整艘船的数据时检查一次 nextline。例如:

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

【讨论】:

  • 修改现有代码的更简单方法是将函数编写为 nextLine() 和 nextInt() 的别名,并包含检查;他们可能会抛出异常以将您拉出现有循环。
  • @Matt nextLine()nextInt() 如果数据用完,肯定会抛出异常。
  • @khelwood 没错,这是我的一个愚蠢的疏忽。毕竟,最初的问题是那些异常没有被捕获。实际上,抛出的特定异常使他看起来好像实际上在他的文件中有这些 cmets,或者出现了问题。
【解决方案2】:

它给你带来麻烦的原因是当用户输入一个整数然后按回车时,刚刚输入了两件事 - 整数和一个“换行符”,即 \n。您正在调用的方法“nextInt”仅读取整数,从而将换行符留在输入流中。但是调用 nextLine() 确实会读入换行符,这就是为什么您必须在代码工作之前调用 nextLine() 的原因。你也可以调用 next(),它也会读入换行符。

另请阅读 Scanner 类的文档以进一步了解:

这是更正后的代码:

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

}

【讨论】:

  • 捕捉错误的加分项
  • @HovercraftFullOfEels 这些是我一年前开始学习 JDBC 的 PreparedStatement 时遇到的问题。