【问题标题】:While loop with JOptionPane returning StringIndexOutOfBounds Exceptions带有 JOptionPane 的 While 循环返回 StringIndexOutOfBounds 异常
【发布时间】:2019-12-25 16:46:15
【问题描述】:

在我的代码中,我有一个 while 循环,其中嵌套了 3 个 IF 测试,这些测试具有由 ELSE 触发的标志:

[test1] 检查输入值的长度是否正好为 1 [防止用户输入任何内容]

[test2] 检查索引 0 处的输入值是否为数字[我需要一个数字作为输入,但我使用的是 JSWING]

[test3]检查输入值长度是否大于1[2位(10,11,12,...)

 num1= JOptionPane.showInputDialog(null,"Please input Guess #" + (counter+1), "0"); 
                 while(exit == false || test1 == false || test2 == false || test3 == false) {
                     if(num1.length() < 1) {
                         JOptionPane.showMessageDialog(null,"Input required");
                         num1= JOptionPane.showInputDialog(null,"Please input Guess #" + (counter+1), "0");
                     }
                     else {
                         test1 = true;
                     }
                     if(Character.isDigit(num1.charAt(0)) == false) {
                         JOptionPane.showMessageDialog(null,"Input has to be a number between 0 - 9.");
                         num1= JOptionPane.showInputDialog(null,"Please input Guess #" + (counter+1), "0");
                     }
                     else {
                         test2 = true;
                     }
                     if(num1.length() > 1) {
                         JOptionPane.showMessageDialog(null,"Input has to be a number between 0 - 9.");
                         num1= JOptionPane.showInputDialog(null,"Please input Guess #" + (counter+1), "0");
                     }
                     else {
                         test3 = true;
                     }
                     if(test1 == true && test2 == true && test3 == true) {
                         exit = true;
                     }

我遇到的问题介于第一次和第二次测试之间。当我尝试不输入任何值作为值 [“” / 或者只是有一个空框并按 Enter] 时,它会检测到没有任何内容的错误并显示一次“需要输入”,但是一旦它循环,它就会输出一个 StringIndexOutOfBoundsException 第二个审判 它适用于我尝试过的所有其他情况(无输入 -> 正确,无输入 -> 不正确......)只有连续无输入的情况会使程序崩溃。

据说错误在这一行,但我不明白在哪里,或者如何。

if(Character.isDigit(num1.charAt(0)) == false)

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:48)
at java.base/java.lang.String.charAt(String.java:709)
at oof.Lottery_Swing_FIX.main(Lottery_Swing_FIX.java:56)

固定逻辑

                JOptionPane.showMessageDialog(null,"Enter 3 one-digit positive numbers for your 3 guesses");
             for(int counter = 0; counter < LIMIT; counter++) {
                 test = false; 

                 while(exit == false || test == false) {
                     num1= JOptionPane.showInputDialog(null,"Please input Guess #" + (counter+1), ""); 
                     if(num1.length() < 1 || Character.isDigit(num1.charAt(0)) == false || num1.length() > 1) {
                         JOptionPane.showMessageDialog(null,"Integer between 1-9 required");
                     }
                     else {
                         test = true;
                     }
                     if(test == true) {
                         numberInput = Integer.parseInt(num1);
                         exit = true;
                     }
                     else {
                         continue;
                     }
                 }

【问题讨论】:

  • 好吧,如果你不输入任何东西,你要求使用重新输入一些东西(num1= JOptionPane.showInputDialog(null,"Please input Guess #" + (counter+1), "0");。然后紧接着,你有if(Character.isDigit(num1.charAt(0)) == false) {。所以如果你不输入任何第二次,它都会失败,因为您尝试访问空字符串的第一个字符。
  • 我将如何解决这个问题?我理解这个问题,但没有真正的解决方法。我应该为 num1 设置另一个输入吗?
  • 重做你的逻辑。您应该在循环中只询问一次该值。它应该看起来像:boolean valid = false; while (!valid) { num1 = getValue(); valid = validateAndShowErrorMessageIfInvalid(num1); }
  • 我更新了我的帖子,它现在可以工作了,但是有没有办法添加单独的消息,详细说明输入过程中出现的问题?例如,如果他们有一个空输入,或者他们输入了所有字母。由于现在每个错误都只输出“需要 1-9 之间的整数”
  • 当然。在方法 validateAndShowErrorMessageIfInvalid() 中,使用 if 块来检查错误。每次发现错误时,显示相应的错误信息,然后返回 false。按照我的解释重构你的代码。将所有内容放在同一个方法中会使推理变得更加困难,并且不允许在发现错误后立即使用return

标签: java swing if-statement indexoutofboundsexception charat


【解决方案1】:

您的“修复”不处理 null,如果对话框关闭 (x) 或取消 Cancel 按钮被选中。您不能像使用 Null String 那样针对 String#length() 方法播放 null em> ("") 所以,你需要在你的代码中检查这个,否则你可能会得到一个 NullPointerException。您可以在您的第一个 if 语句中作为条件组件执行此操作:

if (num1 == null) {
    // The CANCEL or dialog close button was selected.
}

您的代码中确实不需要那些布尔标志。事情会发生,或者根本不会发生。你真的不需要旗帜来提醒你离家这么近(可以这么说)。如果您在 if 语句中正确建立了条件并使用 else if,则不需要它们。话虽如此,您也不需要在 while 循环的条件中使用这些布尔标志。

while 循环需要关注一件事……提示提供了有效数据。如果不是,则保存提示数据的变量 (num1) 将转换为空字符串 ("")。所以在现实中:

String num1 = "";
while (num1.equals("")) { .... }

所以,只要 num1 包含一个空字符串 (""),我们就会继续循环,从而重新提示正确输入。

在您的代码中,您希望向用户提供有关其输入失败原因的具体详细信息。有几种方法可以做到这一点,但是无论您选择哪种方式,请确保它不会生成任何可能最终停止您的应用程序或改变其准确性能的异常(错误)。在当前用例中使用 ifelse if 语句来执行此特定任务没有任何问题。遵循您的特定主题:

int LIMIT = 3, numberInput;
int[] guesses = new int[LIMIT];
String errMsg;
String num1;
JOptionPane.showMessageDialog(null, "<html>You will be prompted three times "
           + "to supply<br>a positive <font color=red><b>single digit</b></font> "
           + "number.</html>", "Information", JOptionPane.INFORMATION_MESSAGE);
for (int counter = 0; counter < LIMIT; counter++) {
    num1 = "";
    while (num1.equals("")) {
        errMsg = "";
        num1 = JOptionPane.showInputDialog(null, "Please input Guess #" + (counter + 1), 
                                           "Guess #" + (counter + 1),JOptionPane.QUESTION_MESSAGE);
        // Does num1 contain null?
        if (num1 == null) {
            if (JOptionPane.showConfirmDialog(null,
                    "<html>You <font color=blue>canceled</font> your input!<br>"
                    + "Do you want to quit?</html>", "Quit",
                    JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
            num1 = ""; // Set for re-prompt.
            continue;
        }
        // Is nothing supplied?
        else if (num1.length() < 1) {
            errMsg = "<html><font size=5 color=red><center>Nothing Supplied!"
                     + "</center></font><br>You must provide a single Integer "
                     + "value between<br>0 and 9 (inclusive).</html>";
        }
        // Is too much supplied?
        else if (num1.length() > 1) {
            errMsg = "<html><center><font size=5 color=red>To Much Supplied!</font><br>" +
                     "<font size=5 color=blue>\"" + num1 + "\"</font></center><br>" +
                     "You must provide a single Integer value between<br>0 and 9 "
                     + "(inclusive).</html>";

        }
        // Is the supplied character a number?
        else if (!Character.isDigit(num1.charAt(0))) {
            errMsg = "<html><center><font size=5 color=red>Invalid Digit Supplied!"
                     + "</font><br><font size=5 color=blue>\"" + num1 + "\"</font>"
                     + "</center><br>You must provide a single Integer value "
                     + "between<br>0 and 9 (inclusive).</html>";
        }

        // Does errMsg actually contain a message? If so display it.
        if (!errMsg.equals("")) {
            JOptionPane.showMessageDialog(null, errMsg, "Invalid Input!", 
                                          JOptionPane.WARNING_MESSAGE);
            num1 = ""; // Set for re-prompt.
        }
        else { 
            numberInput = Integer.parseInt(num1);

            // ... do whatever you want to do with numberInput, for example ....
            guesses[counter] = numberInput;
        }
    }
}

// Display User's LIMITED guesses:
StringBuilder sb = new StringBuilder();
sb.append("<html>The <font color=red><b>").append(LIMIT).
        append("</b></font> Guesses supplied by User are:<br><br>");

for (int i = 0; i < guesses.length; i++) {
    sb.append("Guess #").append((i + 1)).append(":  <font color=blue>").append(guesses[i]).append("</font><br>");
}
sb.append("</html>");

JOptionPane.showMessageDialog(null, sb.toString(), "Guesses Provided", 
                              JOptionPane.INFORMATION_MESSAGE);

如您所见,向用户提供有关输入失败的详细信息需要更多代码。如果您决定只需要一个简单的“无效输入!”,则可以删除所有这些代码。信息。这实质上会迫使用户更加密集地阅读提供的提示,例如:

int LIMIT = 3;
int numberInput;
int[] guesses = new int[LIMIT];
String num1;
JOptionPane.showMessageDialog(null, "<html>You will be prompted three times "
        + "to supply<br>a positive <font color=red><b>single digit</b></font> "
        + "number.</html>", "Information", JOptionPane.INFORMATION_MESSAGE);
for (int counter = 0; counter < LIMIT; counter++) {
    num1 = "";
    while (num1.equals("")) {
        num1 = JOptionPane.showInputDialog(null, "Please input Guess #" + (counter + 1), 
                                           "Guess #" + (counter + 1),JOptionPane.QUESTION_MESSAGE);
        // Does num1 contain null?
        if (num1 == null){
            if (JOptionPane.showConfirmDialog(null,
                    "<html>You <font color=blue>canceled</font> your input!<br>"
                    + "Do you want to quit?</html>", "Quit",
                    JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
            num1 = ""; // Set for re-prompt.
        }
        else if (!num1.matches("\\d")) {
            JOptionPane.showMessageDialog(null, "<html><center><font size=5 color=red>Invalid Input Supplied!</font><br>" +
                    "<font size=5 color=blue>\"" + num1 + "\"</font></center><br>" +
                    "You must provide a single Integer value between<br>0 and 9 "
                    + "(inclusive).</html>", "Invalid Input!", JOptionPane.WARNING_MESSAGE);
            num1 = "";
        }
        else { 
            numberInput = Integer.parseInt(num1);

            // ... do whatever you want to do with numberInput, for example ....
            guesses[counter] = numberInput;
        }        
    }
}

// Display User's LIMITED guesses:
StringBuilder sb = new StringBuilder();
sb.append("<html>The <font color=red><b>").append(LIMIT).
        append("</b></font> Guesses supplied by User are:<br><br>");

for (int i = 0; i < guesses.length; i++) {
    sb.append("Guess #").append((i + 1)).append(":  <font color=blue>").append(guesses[i]).append("</font><br>");
}
sb.append("</html>");
JOptionPane.showMessageDialog(null, sb.toString(), "Guesses Provided", 
                                  JOptionPane.INFORMATION_MESSAGE);

请特别注意上述代码中 else if 语句 (!num1.matches("\\d)) 的条件。这里String#matches() 方法的使用与一个小的Regular Expression 一起使用,即"\\d" 表达式。此表达式告诉 ma​​tches() 方法查看我们匹配的字符串(在 num1 中)是否为 单个数字 字符串数值(例如:“5”)。那么,else if 语句在问什么:

else if num1 中包含的字符串是 NOT (!) 单个数字字符串数值然后在我的花括号中运行代码({...})。这基本上涵盖了除 null 之外的所有输入失败(因为我们将其作为 quit 选项处理)并且String#matches() 方法将不接受 null。

如果您不想要 quit 选项,那么您的代码中只需要一个 if 语句:

if (num1 == null || !num1.matches("\\d")) { ... }

【讨论】:

    猜你喜欢
    • 2013-09-21
    • 1970-01-01
    • 1970-01-01
    • 2019-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-06
    • 2015-11-17
    相关资源
    最近更新 更多