简体   繁体   中英

IndexOutOfBoundsException using ArrayList

I have a option for the user to pick a Month. I set a listener ItemListener for my ComboBox which contains list of Months. I have a set condition where if the user pick "February" list of days will only up to 29 else "April","June" and so on will have 30 days on my ComboBox. But when I choose "February" it works fine but when I select another month I get an error.

IndexOutOfBoundsException: Index: 30, Size: 29

I know this error occur because the another month has a Index of 30. I'm little bit confuse should I remove the content of ArrayList or the ComboBox? Any help how can I eliminate this?

private ItemHandler handler = new ItemHandler();

ArrayList<String> daysList = new ArrayList<String>();

String[] daysObj = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15",
        "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"};
 DefaultComboBoxModel daysModel = new DefaultComboBoxModel(daysObj);

public AddEmployee() 
{
  setMonths();
  setDays();
  cbMonths.addItemListener(handler);
}

private void setDays()
{   
    for(int i = 0; i < daysObj.length; i++)
    {
        daysList.add(daysObj[i]);
    }

    cbDays.setModel((ComboBoxModel)daysModel);   
}

private class ItemHandler implements ItemListener
{
    int removeDays[] = {29,30};//array
    int remove[] = {30};
    @Override
    public void itemStateChanged(ItemEvent e) 
    {
        if(e.getSource() == cbMonths)//Check where combobox occured.
        {
            if(cbMonths.getSelectedItem().equals("February"))
            {
                for(int i = removeDays.length-1; i >= 0; i--)
                {
                    daysList.remove(removeDays[i]);//Remove given array from ArrayList using removeDays[]
                    System.out.println("NEW ELEMENT: "+daysList);
                }

                for(String s : daysList)//Update ArrayList
                {
                    cbDays.addItem(s);
                    System.out.println("NEW LIST OF ARRAY: "+s);
                }

            }
            else if(cbMonths.getSelectedItem().equals("April") || cbMonths.getSelectedItem().equals("June") || 
                    cbMonths.getSelectedItem().equals("September") || cbMonths.getSelectedItem().equals("November"))
            {
                for(int i = remove.length-1; i >= 0; i--)
                {
                    daysList.remove(remove[i]);
                    System.out.println(daysList);
                }

                for(String a : daysList)//Update ArrayList
                {
                    cbDays.addItem(a);
                    System.out.println("NEW LIST OF ARRAY: "+a);
                }

            }
      }
}

I tried a method removeAllItems() but it look likes it doesn't work. cbDays.removeAllItems();

Instead of doing complex calculations each time a user chooses another month (which is hard to read and error prone), better initialize some static models which cover all cases. Your StateChaged handler then only has to pick the correct model. Following example is based on the new fancy java 8 datetime API:

private static String[] initDays( int number )
{
    String[] result = new String[ number];

    for ( int i = 0; i < result.length; i++ )
    {
        result[i] = "" + ( i+1);
    }

    return result;
}

private static final String[] days28 = initDays( 28);
private static final String[] days29 = initDays( 29);
private static final String[] days30 = initDays( 30);
private static final String[] days31 = initDays( 31);

private static final ComboBoxModel<String> model28 = new DefaultComboBoxModel<>(days28);
private static final ComboBoxModel<String> model29 = new DefaultComboBoxModel<>(days29);
private static final ComboBoxModel<String> model30 = new DefaultComboBoxModel<>(days30);
private static final ComboBoxModel<String> model31 = new DefaultComboBoxModel<>(days31);

private static final Set<Month> month30 = EnumSet.of(
         Month.FEBRUARY,
         Month.APRIL,
         Month.JUNE,
         Month.SEPTEMBER,
         Month.NOVEMBER
     );
private static final Set<Month> month31 = EnumSet.of(
         Month.JANUARY,
         Month.MARCH,
         Month.MAY,
         Month.JULY,
         Month.AUGUST,
         Month.OCTOBER,
         Month.DECEMBER
     );
private JComboBox<String> cbMonths = new JComboBox<>();
private JComboBox<String> cbDays = new JComboBox<>();

public void itemStateChanged(ItemEvent e)
{
    if(e.getSource() == cbMonths)//Check where combobox occured.
    {
        if(cbMonths.getSelectedItem().equals("February"))
        {
            Month selectedMonth = Month.valueOf( cbMonths.getItemAt( cbMonths.getSelectedIndex() ) );

            if ( month31.contains( selectedMonth ) )
            {
                cbDays.setModel( model31 );
            }
            else if ( month30.contains( selectedMonth ) )
            {
                cbDays.setModel( model30 );
            }
            else
            {
                if ( Year.isLeap( Instant.now().getLong( ChronoField.YEAR ) ) )
                {
                    cbDays.setModel( model29 );
                }
                else
                {
                    cbDays.setModel( model28 );
                }
            }
        }
    }
}

A further enhancement could be to use a cbMonth which is directly typed by the Month enum, and provide a cell renderer which displays the month in the locale of the user.

After initialization via setDays() daysList contains 31 elements. When February is selected, two elements with the index 29 and 30 are removed:

    daysList.remove(removeDays[i])

daysList is now having 29 elements. When another month is selected, one element with index 30 is removed

    daysList.remove(remove[i]);

But dayslist only has 29 elements, so an IndexOutOfBoundsException is thrown.

Therefore one solution might be to re-initialize daysList everytime itemStateChanged is triggered.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM