我有一个家庭作业来创建一个带有循环菜单的类来管理汽车队列。我们在上一节课中学习了队列。
我的菜单完全正常,直到它捕获InputMismatchException
或QueueEmptyException
,之后它会进入无限循环,甚至不会停留在userInput.nextInt();
。它在捕获QueueFullException
时起作用,但在其他捕获时不起作用。
我的代码是:
import java.util.*;
public class CarQueueManagement {
public static void main(String[] args) throws InputMismatchException, QueueFullException{
ArrayQueue queue = new ArrayQueue(3);;
Scanner userInput = new Scanner(System.in);
int carNum;
int choice = 0;
queue.add(1);
OUTER:
while (true) {
try{
System.out.println("ΜΕΝΟΥ:\n\t1. Άφιξη αυτοκινήτου");
System.out.println("\t2. Αναχώρηση αυτοκινήτου\n\t3. Κατάσταση ουράς\n\t4. Έξοδος");
System.out.print("\n\tΕπιλογή (1-4): ");
choice = userInput.nextInt();
switch (choice){
case 1:
System.out.print("\n\tΆφιξη αυτοκινήτου:\n\t\tΑριθμός Αμαξιού");
carNum = userInput.nextInt();
queue.add(carNum);
break;
case 2:
if(queue.isEmpty()){
System.out.println("\n\tΗ ουρά είναι άδεια, δεν χριάζεται διαγραφή.\n\n");
break;
}
String answer;
while(true){
System.out.print("\n\tΑναχώρηση αυτοκινήτου\n\t\tΕπιβεβαίωση; (y/n): ");
answer = userInput.next();
if(answer.equals("y")){
queue.remove();
break;
}
else if(answer.equals("n"))
break;
}
break;
case 3:
System.out.println("\n\tΚατάσταση ουράς:");
if(queue.isEmpty()) System.out.println("\t\tΗ ουρά είναι άδεια.\n\n");
else if(queue.isFull()) System.out.println("\t\tΗ ουρά είναι γεμάτη.\n\n");
else System.out.println("\t\tΗ ουρά έχει άδιες θέσοις.\n\n");
break;
case 4:
System.out.print("\n\nΕξοδος");
break OUTER;
default:
break;
}
}catch (InputMismatchException exc){
System.out.println("\t\tΛΑΘΟΣ ΕΙΣΑΓΩΓΗ\n");
}catch(QueueEmptyException exc){
System.out.println("\t\t" + exc.getMessage() + "\n");
}catch(QueueFullException exc){
System.out.println("\t\t" + exc.getMessage() + "\n");
}
}
}
}
答案 0 :(得分:1)
从java.util.Scanner
docs(强调我的)的介绍部分:
当扫描程序抛出
InputMismatchException
时,扫描程序将不会传递导致异常的令牌,以便可以通过其他方法检索或跳过它。
如果没有详细信息,您的while(true)
循环就是:
while (true) {
try{
choice = userInput.nextInt();
switch (choice){
case 1:
...
}
} catch (InputMismatchException exc){
// Do nothing.
}
}
当用户输入无法转换为整数的内容时,Scanner
会抛出InputMismatchException
,您会抓住并忽略它。然后while
循环返回到顶部,尝试执行userInput.nextInt()
...但Scanner
仍在查看相同的无效输入,所以它立即抛出另一个InputMismatchException
,你抓住并再次忽略它。执行继续在while
循环的顶部,再次调用nextInt()
......循环将永远持续。
您必须强制Scanner
跳过错误输入,因此您的catch
块应如下所示:
}catch (InputMismatchException exc){
System.out.println("\t\t[chastise the user in Greek]\n");
userInput.next(); // Skip invalid input.
}
作为一般规则,许多小方法比一种大方法更容易理解。嵌套的while
循环和switch
语句特别难以理解。我只能通过将这个巨大的main
方法分解为许多较小的私有静态方法来找到错误。
至少,每个菜单项都可以用自己的方法处理。我还通过将整个菜单放入一个单独的方法来删除break
标签,该方法返回boolean
,指示用户是否完成。这将main
内的整个循环减少为:
boolean done = false;
while (! done) {
try{
done = handleUserInput(queue, userInput);
} catch (InputMismatchException exc) {
System.out.println("\nINPUT ERROR\n");
userInput.next();
} // Other catch blocks as before...
}
我的handleUserInput
做得不多 - 它获取用户输入,确定哪个方法应该处理该输入,然后返回true
或false
...也可以比这简单。
private static boolean handleUserInput(
final ArrayQueue queue,
final Scanner userInput
) {
boolean done = false;
printMenu();
int choice = userInput.nextInt();
switch (choice) {
case 1:
addToQueue(queue, userInput);
break;
case 2:
removeFromQueue(queue, userInput);
break;
case 3:
displayQueue(queue);
break;
case 4:
printExitMessage();
done = true;
break;
default:
break;
}
return done;
}
将各种菜单活动拆分为不同的方法,使得 更容易理解。例如,当逻辑在main
中混合在一起时,很难判断carNum
或answer
之类的变量是否是问题的一部分。在此版本中,carNum
是一个陷入addToQueue
方法内的局部变量,所以当我在其他任何地方工作时,我可以完全忽略它。