Java程序无法输出及InputMismatchException错误排查求助
Hey there, let's work through your Java program issues step by step. You've hit two distinct problems, so we'll tackle each one and fix the code properly.
1. 第一个问题:主方法缺失
你最初遇到的错误是因为主方法放在了独立的Driver类中,但你直接运行了Township类。Java要求被运行的类必须包含public static void main(String[] args)方法(JavaFX应用除外)。你把主方法移到Township类的方向是对的,但这引出了第二个问题。
2. 第二个问题:InputMismatchException
这个异常发生在Scanner试图读取某一类型的值(比如int)但遇到了其他内容(字符串、空行或格式错误)时。我们来拆解问题所在并修复:
问题1:文件读取格式不匹配
你的readFile方法假设bicycledata.txt的格式是这样的:
TownshipName 100 50 AnotherTown 200 150
如果你的文件格式不同(比如每个镇的所有数据在一行),nextLine()和nextInt()的调用就会不同步,导致异常。另外,调用nextInt()后需要正确处理换行符,我们可以通过更安全的方式读取每行内容并解析值。
问题2:用户输入的Scanner同步问题
在getInput方法中,用sc.nextInt()读取家庭数和自行车数后,输入缓冲区中残留的换行符会被下一个sc.nextLine()读取,导致你回到菜单选择选项1时,得到的镇名是空字符串。
修复后的完整代码(带注释说明)
以下是修复了所有问题的代码,注释标注了关键修改点:
import java.util.*; import java.io.*; public class Township { // 实例变量 String name; int households; int bicycles; double average; String tier; double funding; public static void main(String[] args) throws IOException { Scanner sc = new Scanner(System.in); Township town[] = new Township[10]; int count = readFile(town); while (true) { System.out.println("1. Input\n2. Report\n3. Exit"); System.out.print("Enter choice: "); // 增加输入校验,确保用户输入整数 while (!sc.hasNextInt()) { System.out.println("Please enter a valid number (1-3)!"); sc.next(); // 消耗无效输入 } int choice = sc.nextInt(); sc.nextLine(); // 消耗选择后的换行符 switch (choice) { case 1: town[count] = getInput(sc); count++; break; case 2: printReport(town, count); break; case 3: writeFile(town, count); System.out.println("Goodbye!"); return; default: System.out.println("Invalid choice, please pick 1, 2, or 3."); } } } // 构造方法 public Township(String name, int households, int bicycles) { this.name = name; this.households = households; this.bicycles = bicycles; // 创建对象时自动计算相关值,避免遗漏调用 calculateAverageBikes(); calculateFunding(); calculateTier(); } // 重命名方法以遵循Java驼峰命名规范 private void calculateAverageBikes() { average = (double) bicycles / households; } private void calculateFunding() { if (average >= 3.0) funding = 50000.00; else if (average >= 2.0) funding = 40000.00; else if (average >= 1.0) funding = 30000.00; else if (average >= 0.5) funding = 20000.00; else funding = 0.00; } private void calculateTier() { if (average >= 3.0) tier = "One"; else if (average >= 2.0) tier = "Two"; else if (average >= 1.0) tier = "Three"; else if (average >= 0.5) tier = "Four"; else tier = "Five"; } // 按镇名字母顺序排序 public static void sort(Township[] townships, int count) { for (int i = 0; i < count - 1; i++) { for (int j = i + 1; j < count; j++) { if (townships[i].name.compareTo(townships[j].name) > 0) { Township temp = townships[i]; townships[i] = townships[j]; townships[j] = temp; } } } } // 向控制台打印报告 public static void printReport(Township[] townships, int count) { sort(townships, count); System.out.println("---------------------------------------------------------------------------------------------------"); System.out.printf("%-20s%-15s%-18s%-20s%-20s%s\n", "Township Name", "Households", "Bicycles Reported", "Average Bikes/Household", "Proposed Funding", "Tier Designation"); System.out.println("---------------------------------------------------------------------------------------------------"); for (int i = 0; i < count; i++) { System.out.printf("%-20s%-15d%-18d%-20.2f%-20.2f%s\n", townships[i].name, townships[i].households, townships[i].bicycles, townships[i].average, townships[i].funding, townships[i].tier); } } // 安全获取用户输入 public static Township getInput(Scanner sc) { System.out.print("Enter the name of Township: "); String name = sc.nextLine(); // 校验家庭数输入 int households = 0; while (true) { System.out.print("Enter the number of households: "); if (sc.hasNextInt()) { households = sc.nextInt(); if (households > 0) break; // 确保是正数 else System.out.println("Households must be a positive number!"); } else { System.out.println("Please enter a valid integer for households."); sc.next(); // 消耗无效输入 } } // 校验自行车数输入 int bicycles = 0; while (true) { System.out.print("Enter the number of bicycles reported: "); if (sc.hasNextInt()) { bicycles = sc.nextInt(); if (bicycles >= 0) break; // 非负数 else System.out.println("Bicycles can't be negative!"); } else { System.out.println("Please enter a valid integer for bicycles."); sc.next(); // 消耗无效输入 } } sc.nextLine(); // 消耗最后一个整数输入后的换行符 return new Township(name, households, bicycles); } // 安全读取文件(处理常见格式问题) public static int readFile(Township[] townships) throws IOException { int count = 0; File file = new File("bicycledata.txt"); // 读取前检查文件是否存在 if (!file.exists()) { System.out.println("Warning: bicycledata.txt not found, starting with empty list."); return count; } Scanner fileScanner = new Scanner(file); while (fileScanner.hasNextLine() && count < townships.length) { String name = fileScanner.nextLine().trim(); // 跳过文件中的空行 if (name.isEmpty()) continue; // 读取家庭数 if (!fileScanner.hasNextInt()) { System.out.println("Invalid data in file for households, skipping entry: " + name); // 跳过该条目剩余的行 while (fileScanner.hasNextLine()) { if (fileScanner.hasNextInt()) break; fileScanner.nextLine(); } continue; } int households = fileScanner.nextInt(); fileScanner.nextLine(); // 消耗换行符 // 读取自行车数 if (!fileScanner.hasNextInt()) { System.out.println("Invalid data in file for bicycles, skipping entry: " + name); while (fileScanner.hasNextLine()) fileScanner.nextLine(); continue; } int bicycles = fileScanner.nextInt(); fileScanner.nextLine(); // 消耗换行符 if (households > 0 && bicycles >= 0) { townships[count] = new Township(name, households, bicycles); count++; } else { System.out.println("Invalid values for " + name + ", skipping (households must be positive, bicycles non-negative)."); } } fileScanner.close(); return count; } // 写入报告到文件 public static void writeFile(Township[] townships, int count) throws IOException { sort(townships, count); // 使用try-with-resources自动关闭写入流 try (PrintWriter pout = new PrintWriter(new FileWriter("report.txt"))) { pout.println("---------------------------------------------------------------------------------------------------"); pout.printf("%-20s%-15s%-18s%-20s%-20s%s\n", "Township Name", "Households", "Bicycles Reported", "Average Bikes/Household", "Proposed Funding", "Tier Designation"); pout.println("---------------------------------------------------------------------------------------------------"); for (int i = 0; i < count; i++) { pout.printf("%-20s%-15d%-18d%-20.2f%-20.2f%s\n", townships[i].name, townships[i].households, townships[i].bicycles, townships[i].average, townships[i].funding, townships[i].tier); } } } }
关键修改点:
- 主方法位置:将主方法保留在
public Township类中,确保Java运行时能找到它。 - 输入校验:为用户和文件输入添加了整数校验,防止
InputMismatchException。 - Scanner同步:修复了
nextInt()后的换行符处理问题,避免镇名输入为空。 - 文件读取鲁棒性:增加了文件存在性检查、空行跳过,遇到无效数据时优雅处理而非崩溃。
- Java命名规范:将
AverageBikes()这类方法重命名为calculateAverageBikes(),遵循驼峰命名法。 - 自动计算:将平均值、资金、等级计算移到构造方法中,确保创建对象时自动执行,避免遗漏调用。
- 资源自动管理:使用try-with-resources处理文件写入,确保流能正确关闭。
bicycledata.txt要求的格式:
确保你的输入文件采用以下结构(每个镇占3行):
Springfield 200 450 Shelbyville 150 300
如果你偏好其他格式(比如每行逗号分隔数据),可以告诉我,我们再调整readFile方法。
内容的提问来源于stack exchange,提问作者RobIsNotATechGuy

