Forum Stats

  • 3,733,760 Users
  • 2,246,818 Discussions
  • 7,856,869 Comments

Discussions

How do I charAt In a Input with a variable length, without getting the StringIndexOutOfBoundsExcepti

Dynami
Dynami Member Posts: 9
edited August 2017 in New To Java

Hello. I've been trying to make a timer in an applet, by making it

1. You input the Hours:Minutes:Seconds

2. The program will separate them into different ints.

3. It will subtract 1 from the "Sec" Int every second, and when Sec runs out it will subtract from Min, And when it ends it will subtract from Hour, and at last, Play a sound.

But, because not always you will have Hours or Minutes on the timer, when I try to use charAt to extract the digits (on the second step) some times it throws a StringIndexOutOfBoundsException.

I'm probably doing the unefficient way, and I'm certain that I have more than 1 mistake in my code.

I am not asking someone to spoonfeed the code. But I would really appreciate if someone could enlighten on what I'm doing wrong here.

Thanks in advance.

(Also, this code is uncompilable. But I will ask about that in another discussion.)

  private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {                                           

        int HMS = Integer.parseInt(jTextField1.getText());

      String HourMinSec = Integer.toString(HMS);

if(HourMinSec.regionMatches(0,"00000",0,5)){

     int Sec = (int) HourMinSec.charAt(0);

     int Min = 0;

     int Hour = 0;

     } else

{ if (HourMinSec.regionMatches(0,"0000",0,4)){

     int Sec = (int) HourMinSec.charAt(0) * 10 + (int) HourMinSec.charAt(1);

     int Min = 0;

     int Hour = 0;} else{

   if (HourMinSec.regionMatches(0,"000",0,4)){

     int Sec = (int) HourMinSec.charAt(1) * 10 + (int) HourMinSec.charAt(2);

     int Min = (int) HourMinSec.charAt(0);

     int Hour = 0;}

     else {

      if(HourMinSec.regionMatches(0,"00",0,2)){ 

      int Sec = (int) HourMinSec.charAt(2) * 10 + (int) HourMinSec.charAt(3);

      int Min = (int) HourMinSec.charAt(0) * 10 + (int) HourMinSec.charAt(1);

      int Hour = 0;

      } else {

      if(HourMinSec.regionMatches(0,"0",0,1)){ 

      int Sec = (int) HourMinSec.charAt(3) * 10 + (int) HourMinSec.charAt(4);

      int Min = (int) HourMinSec.charAt(1) * 10 + (int) HourMinSec.charAt(2);

      int Hour =(int) HourMinSec.charAt(0);

      } else {

      int Sec = (int) HourMinSec.charAt(4) * 10 + (int) HourMinSec.charAt(5);

      int Min = (int) HourMinSec.charAt(2) * 10 + (int) HourMinSec.charAt(3);

      int Hour =(int) HourMinSec.charAt(0) * 10 + (int) HourMinSec.charAt(1);}}}}

      while(Sec != 0 || Min != 0 || Hour != 0){

          Thread.sleep(9);

        Sec -= 1;

        if(Sec == 0){

         Min -= 1;

          Sec = 60;}

        if(Min == 0){

            Hour -= 1;

            Min = 59;

        }

      jTextField1.setText(Hour + ":" + Min + ":" + Sec);

    }

     

    }                          

Tagged:
mNem

Best Answer

  • mNem
    mNem Member Posts: 1,380 Gold Trophy
    edited August 2017 Accepted Answer

    1. For StringIndexOutOfBoundsException:

          int HMS = Integer.parseInt(jTextField1.getText()); //line A      
          String HourMinSec = Integer.toString(HMS); //line B

    line A converts the user input to an int that gets rid of all leading zeros if any in the input. ie.,

    "00005" --> 5

    then, in line B, the conveted int is turned into a string and passed to the rest of the method.

    so, the conditions are checking for "5"

    so, all your subsequent checks for regionmatches fail to match any because line A parseInt() call got rid of all leading zeros. I have removed the code within the blocks to highlight the issue area.

          if (HourMinSec.regionMatches(0, "00000", 0, 5))      {      }      else      {        if (HourMinSec.regionMatches(0, "0000", 0, 4))        {        }        else        {            if (HourMinSec.regionMatches(0, "000", 0, 4))            {            }            else            {              if (HourMinSec.regionMatches(0, "00", 0, 2))              {              }              else              {                  if (HourMinSec.regionMatches(0, "0", 0, 1))                  {                  }                  else                  {                    // for all your input, you are ending up here                      Sec = (int) HourMinSec.charAt(4) * 10 + (int) HourMinSec.charAt(5);

    To prevent the StringIndexOutOfBoundsException, your input should at least have 6 digits after the leading zeros - remember index starts at 0, so charAt(5) will need six characters to match.

    2. The local variables Sec, Min and Hour are defined in each IF block. they are local to that block and do not have visibility outside that block. Define the variables once at the top.

      private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {      int Sec = 0;      int Min = 0;      int Hour = 0;

    3. int conversion from charAt() call does not return what you think it returns. (edited)

    '0' --> 48'1' --> 49...'9' --> 57

    4. IF -- ELSE -- IF

    Your code block can be simplified

    from

          if (HourMinSec.regionMatches(0, "00000", 0, 5))      {      }      else      {         if (HourMinSec.regionMatches(0, "0000", 0, 4))         {         }         else         {            if (HourMinSec.regionMatches(0, "000", 0, 4))            {

    to

          if (HourMinSec.regionMatches(0, "00000", 0, 5))
          {
             //...
          }
          else if (HourMinSec.regionMatches(0, "0000", 0, 4))
          {
             //...
          }
          else if (HourMinSec.regionMatches(0, "000", 0, 4))
          {

Answers

  • handat
    handat Member Posts: 4,688 Gold Crown
    edited August 2017

    To answer your question first, you can do a int l = HourMinSec.length() to get the length of the String, and when you do a charAt() make sure that that number is not bigger than the length of the String, ie the variable l is less than 3, then don't do charAt(3).

    A hint for later on, use the Calendar class.

  • mNem
    mNem Member Posts: 1,380 Gold Trophy
    edited August 2017 Accepted Answer

    1. For StringIndexOutOfBoundsException:

          int HMS = Integer.parseInt(jTextField1.getText()); //line A      
          String HourMinSec = Integer.toString(HMS); //line B

    line A converts the user input to an int that gets rid of all leading zeros if any in the input. ie.,

    "00005" --> 5

    then, in line B, the conveted int is turned into a string and passed to the rest of the method.

    so, the conditions are checking for "5"

    so, all your subsequent checks for regionmatches fail to match any because line A parseInt() call got rid of all leading zeros. I have removed the code within the blocks to highlight the issue area.

          if (HourMinSec.regionMatches(0, "00000", 0, 5))      {      }      else      {        if (HourMinSec.regionMatches(0, "0000", 0, 4))        {        }        else        {            if (HourMinSec.regionMatches(0, "000", 0, 4))            {            }            else            {              if (HourMinSec.regionMatches(0, "00", 0, 2))              {              }              else              {                  if (HourMinSec.regionMatches(0, "0", 0, 1))                  {                  }                  else                  {                    // for all your input, you are ending up here                      Sec = (int) HourMinSec.charAt(4) * 10 + (int) HourMinSec.charAt(5);

    To prevent the StringIndexOutOfBoundsException, your input should at least have 6 digits after the leading zeros - remember index starts at 0, so charAt(5) will need six characters to match.

    2. The local variables Sec, Min and Hour are defined in each IF block. they are local to that block and do not have visibility outside that block. Define the variables once at the top.

      private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {      int Sec = 0;      int Min = 0;      int Hour = 0;

    3. int conversion from charAt() call does not return what you think it returns. (edited)

    '0' --> 48'1' --> 49...'9' --> 57

    4. IF -- ELSE -- IF

    Your code block can be simplified

    from

          if (HourMinSec.regionMatches(0, "00000", 0, 5))      {      }      else      {         if (HourMinSec.regionMatches(0, "0000", 0, 4))         {         }         else         {            if (HourMinSec.regionMatches(0, "000", 0, 4))            {

    to

          if (HourMinSec.regionMatches(0, "00000", 0, 5))
          {
             //...
          }
          else if (HourMinSec.regionMatches(0, "0000", 0, 4))
          {
             //...
          }
          else if (HourMinSec.regionMatches(0, "000", 0, 4))
          {
  • mNem
    mNem Member Posts: 1,380 Gold Trophy
    edited August 2017

    Forgot to add:

    For item #2: Remove the repeated definitions of Local variables (Sec, Min and Hour).

    if(HourMinSec.regionMatches(0,"00000",0,5)){    int Sec = (int) HourMinSec.charAt(0);    int Min = 0;    int Hour = 0;    } else

    On a general note, why don't you want to request the user input as the more commonly known format hh:mi:ss. this would make your task easier.

    I would suggest that you comment out the sleep() and run the block with System.out.println() version while fixing it.

             while (Sec != 0 || Min != 0 || Hour != 0)
             {
                //Thread.sleep(9);
                Sec -= 1;
                if (Sec == 0)
                {
                   Min -= 1;
                   Sec = 60;
                }
                if (Min == 0)
                {
                   Hour -= 1;
                   Min = 59;
                }            //jTextField1.setText(Hour + ":" + Min + ":" + Sec);
                System.out.println(Hour + ":" + Min + ":" + Sec);
             }
  • Unknown
    edited August 2017

    You seem to be trying to write code BEFORE you have defined and documented all of the requirements.

    And you then should be writing pseudo-code that says, in English, what each step does.

    Next you walk through each step manually and verify that it does what you think it does.

    The BIGGEST problem with your code and process is you are making it WAY TOO COMPLICATED

    Hello. I've been trying to make a timer in an applet, by making it1. You input the Hours:Minutes:Seconds2. The program will separate them into different ints.

    Get the user input the SIMPLE way. Create a drop-down for hours, another for minutes and another for seconds. That way the only choices the user has is 1-24 for hour, 0-59 for minutes and 0-59 for seconds.

    Convert the strings for hour, minute and second to 'int'.

    Then use simple nested loops:

    for (hour ...) {  for (minute ...) {    for (second ...) {        sleep for one second        display the hour:minute:second      }  }}

    The ONLY real code you need is the sleep one second and the display.

    The outer FOR loop automatically counts down the hours ('for (hour = startHour; hour >= 0; hour --')).

    The 'minute' FOR loop automatically counts down the minutes.

    The 'second' for loop automatically counts down the seconds.

    The above is pretty TRIVIAL.

    Suggestion: ALWAYS do things the simplest, possible way until you have something that actually works properly. Then you can clutter it up, if necessary, with other stuff.

    mNem
  • Dynami
    Dynami Member Posts: 9
    edited August 2017

    nNem really helped me to understand why my code wasn't working, and rp0428 gave me a really good solution.

    And I would never know about the calendar class if it wasn't handat.

    Big thanks to all of you.

This discussion has been closed.