简体   繁体   中英

Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 6

public class IntegerSet {
int dMax;
boolean[] set;

public IntegerSet(int domainMax) {
    dMax = domainMax + 1;
    set = new boolean[dMax];

}
...some methods...

public static IntegerSet union(IntegerSet s1, IntegerSet s2) {
    IntegerSet union = new IntegerSet(Math.max(s1.dMax, s2.dMax));
    for (int i = 0; i < (Math.max(s1.dMax, s2.dMax)); i++) {

        union.set[i] = (s1.set[i] || s2.set[i]);
    }

    return union;
}

Can anyone tell me whats wrong with this?

I can't understand why I'm getting the error message after hours: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6 As the two sets supplied as arguments may have different domain max; the resulting union should have whichever of these two domain max is larger hence why I am using Math.max.

Any help would be appreciated.

This:

dMax = domainMax + 1;

should be:

dMax = domainMax;

Or just use set.length .

Your for-loop goes from 0 to the max size of s1 and s2 . But because (in the situation that throws errors), one of your IntegerSet s is smaller, the for-loop goes past the size of the smaller IntegerSet when retrieving all of the boolean s from the larger IntegerSet

for (int i = 0; i < (Math.max(s1.dMax, s2.dMax)); i++) {

    union.set[i] = (s1.set[i] || s2.set[i]);
}

If the size of one set is smaller than the max, then you are going to get an IndexOutOfBoundsException .

Example:

Say you have the following conditions:

s1 = {0, 1, 1, 0, 1}
s2 = {0, 0, 0}
s1.dMax = 5, so s1.set has a size of 5
s2.dMax = 3, so s2.set has a size of 3

In your for-loop, you are going to iterate from 0 to 4. When the following occurs:

 i = 3
 s1.set[i] = s1.set[3] //IndexOutOfBoundsException because the size of s1.set is 3. 

You have a couple options of how you can fix this:

  • You can add a check in your for-loop to ensure that you aren't
    going to get an IndexOutOfBoundsException for your smaller
    IntegerSet and just set the index in union to the boolean value of your larger set.
  • You can pad to your smaller IntegerSet depending on what you want the union to be for the blank indicies.
  • Use the min size of the two IntegerSet s if you want to ignore the extra boolean s (Judging from the fact that you made the union set the size of the max, I am guess that is not the case)

Side Note: You also do not need to add the +1 to the dMax variable when you create your union IntegerSet . That is going to result in your having an extra index that you don't need and could cause problems later.

The problem arises when s1 and s2 have different lengths. These lines are flawed:

IntegerSet union = new IntegerSet(Math.max(s1.dMax, s2.dMax));
for (int i = 0; i < (Math.max(s1.dMax, s2.dMax)); i++) {

Think about what two sets of unequal length look like: (using 1 and 0 in place of true and false )

s1: {0 1 0 0 1 1}               length = 6
s2: {1 1 1 0 0 0 1 0 1 1 0 1}   length = 12

You've programmed your loop to iterate from 0 up to the maximum length of the two sets, which in the above example is 12 (meaning that the last value your loop will use is 11). But s1 is only 6 elements long--its last valid index is 5! As the loop erroneously attempts to access elements 7 through 12 (indices 6 through 11) of s1 , it throws an ArrayIndexOutOfBoundsException.

To fix this, you should use the minimum length of the two sets in both of the lines where you use the maximum. This way, you will be taking the union:

s1:    {0 1 0 0 1 1}               length = 6
s2:    {1 1 1 0 0 0 1 0 1 1 0 1}   length = 12
union: {1 1 1 0 1 1}               length = min(6, 12) = 6

Instead of

s1:    {0 1 0 0 1 1}! ! ! ! ! !    length = 6; no elements 7 through 12!
s2:    {1 1 1 0 0 0 1 0 1 1 0 1}   length = 12
union: {1 1 1 0 1 1 ! ! ! ! ! !}   length = max(6, 12) = 12 -> errors

This leaves the later section of s2 out of the union, as there are no corresponding elements in s1 to perform a boolean || with. However, you could also do something like this:

IntegerSet union = new IntegerSet(Math.max(s1.dMax, s2.dMax));

for (int i = 0; i < (Math.max(s1.dMax, s2.dMax)); i++) {

    if (s2.set.length > s1.set.length)
    {
        union.set[i] = s2.set[i] || (i < s1.set.length ? s1.set[i] : false);
    }
    else
    {
        union.set[i] = s1.set[i] || (i < s2.set.length ? s2.set[i] : false);
    }
}

This will use false 's for every missing element in the shorter set, resulting in the union being:

s1:    {0 1 0 0 1 1}               length = 6
s2:    {1 1 1 0 0 0 1 0 1 1 0 1}   length = 12
union: {1 1 1 0 1 1 1 0 1 1 0 1}   length = max(6, 12) = 12

All entries are simply copied from the longer set, since anything || false anything || false is itself.

You are using dMax as the number of boolean array elements in one place, and as the domain maximum (wrong) when you create the new union set. (That causes you to make union 1 element too large.)

Several things to consider when you rewrite your code:

  1. Assuming domainMax implies a set of integers from [0, domainMax], do define a boolean array with domainMax+1 elements (don't bother with a dMax variable, you can get that info by checking set.length
  2. In the " union " function, be sure to handle the case where one or both of the input IntegerSet s is null
  3. Use protected set to make sure the internal representation of the IntegerSet is not known or accessed outside your class
  4. When you perform the union of two non-null IntegerSet s, only perform the or operation (||) for the case where both sets have values; then for the "bigger" set, simply copy over the remaining items.

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