简体   繁体   English

遍历列表时出现问题:Java中的IndexOutOfBoundsException

[英]Issue when iterating through lists: IndexOutOfBoundsException in Java

I'm writing a program that applies many principles of computational linguistics. 我正在编写一个应用许多计算语言学原理的程序。 My problem at this moment is the following piece of code form a method that "flexibilizes two definitions". 目前,我的问题是下面的代码形成了一种“使两个定义灵活化”的方法。 This is, it compares two different definitions of the same word, and in each definition empty or blank spaces will be added to later on work with the altered definitions (with blank spaces added). 也就是说,它会比较同一单词的两个不同定义,并且在每个定义中都会添加空白或空格,以供以后使用更改后的定义(添加空白)。 Say we have the following two definitions, defining the term "free fall". 假设我们有以下两个定义,定义了“自由落体”一词。

1) Free fall descent  of a body subjected only to            the   action of  gravity.
2) Free fall movement of a body in        a    gravitational field under  the influence of gravity

There is a list of words called stoplist, which contains the words: "of", "a", "in", "to", and "under". 有一个单词列表,称为“停止列表”,其中包含单词:“ of”,“ a”,“ in”,“ to”和“ under”。 After the process, each word in the definition that is also contained in the stoplist must correspond to a blank space OR another stoplist word of the other definition. 处理之后,定义中还包含在非索引字表中的每个单词必须与空白或另一个定义的另一个非索引字词相对应。 So after executing such process, the previous definitions, represented in two different lists, should look like this: 因此,在执行这样的过程之后,以两个不同的列表表示的先前的定义应如下所示:

1) Free fall descent  of a body ____ ____ subjected     only  to     the action    of gravity.
2) Free fall movement of a body in   a    gravitational field under  the influence of gravity.

The code I wrote to achieve this is the following: 我为实现此目的而编写的代码如下:

[...]

String[] sList = STOPLIST.split(" ");  //this is the stoplist
String[] definition1 = defA1.split(" ");  //this is the array of words of the first definition
String[] definition2 = defA2.split(" ");  //this is the array of words of the second definition
List<String> def1 = new ArrayList<String>();  
List<String> def2 = new ArrayList<String>();
List<String> stopList = new ArrayList<String>();

for(String word : definition1){
    def1.add(word); //I transform arrays into lists this way because I used to think that using .asList() was the problem.
}
for(String word : definition2){
    def2.add(word);
}
for(String word : sList){
    stopList.add(word);
}

int mdef = (def1.size() <= def2.size()) ? def1.size() : def2.size(); //here mdef will have the value of the lenght of the shortest definition, and we are going to use the value of mdef to iterate later on.

for(int i = 0; i < mdef; i++){
   if (stopList.contains(def1.get(i))) {  //here I check if the first word of the first definition is also found in the stoplist.
        if (!stopList.contains(def2.get(i))) {  //If the word of def1 previously checked is in the stoplist, as well as the corresponding word in the second definition, then we won't add a " "(blank) space in the corresponding position of the second definition.
           def2.add(i , " "); //here I add that blank space, only if the stoplist word in def1 corresponds to a non-stoplist word in def2. Again, we do this so the stoplist word in def1 corresponds to a blank space OR another stoplist word in def2.
           if(mdef == def2.size())
               mdef++; //In case the shortest definition is the definition to which we just added spaces, we increment mdef++, because that space added increases the length of the shortest definition, and to iterate in this recenlty extended definiton, we have to increment the index with which we iterate.
        }
    } else if (stopList.contains(def2.get(i))) { //this else if does the same than the previous one, but checks for the second definition instead of the first one. And adds blanks to def1 instead of def2 if necessary.
        if (!stopList.contains(def1.get(i))) {
            def1.add(i , " ");
            if(mdef == def1.size())
                mdef++;
        }
    }
}

[...]

Now, if you analyze the code carefully, you will realize that not all words of the lengthiest list will be checked, given that we iterate ove the definitions using the lenght of the shortest definition as index. 现在,如果您仔细分析代码,您将意识到,由于我们使用最短定义的长度作为索引来迭代定义,因此不会检查最长列表中的所有单词。 This is fine, the remainding words of the lenghtiest definitions don't have to be checked, they will correspond to null spaces of the other definition (in case the lists don't end up being of the same lenght after the addition of spaces, as the previous exaple shows). 很好,不必检查最短定义的其余单词,它们将与另一个定义的空空格相对应(以防在添加空格后列表最终不具有相同的长度,如前一个示例所示)。

Now, after the explanation, the problem is the following: after running the main class, which calls the method that contains the previous code, a runtime exceptions pops out: 现在,在进行了解释之后,问题就出在以下方面:运行主类(调用包含先前代码的方法)后,会弹出运行时异常:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
    at java.util.ArrayList.rangeCheck(ArrayList.java:571)
    at java.util.ArrayList.get(ArrayList.java:349)
    at main2.main(main2.java:75)

I don't understand why it is finding any of the lists as "empty". 我不明白为什么它会找到任何列表为“空”。 I have tried to solve it in too many ways, I hope a I gave a good explanation. 我试图以多种方式解决它,希望我给了很好的解释。

It may help as a clue that if I assign mdef to the lengthiest size instead of the shortest, that is : 作为提示,如果我将mdef分配给最长的而不是最短的大小,那么可能会有所帮助:

int mdef = (def1.size() >= def2.size()) ? def1.size() : def2.size();

the error changes to: 错误更改为:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 15, Size: 15
    at java.util.ArrayList.rangeCheck(ArrayList.java:571)
    at java.util.ArrayList.get(ArrayList.java:349)
    at asmethods.lcc.turnIntoFlex(lcc.java:55)
    at asmethods.lcc.calLcc(lcc.java:99)
    at main2.main(main2.java:73)' 

Where lcc is the class that contains the method turnIntoFlex that contains the piece of code I'm showing. 其中lcc是包含方法turnIntoFlex的类,该方法包含我正在显示的代码段。 The line 55 of "turnIntoFlex" corresponds to the first line of the loop, that is: “ turnIntoFlex”的第55行对应于循环的第一行,即:

if (stopList.contains(def1.get(i))) { [...]

Comments: The values of defA1 and defA2 are the definitions, respectively. 注释:defA1和defA2的值分别是定义。 ie def1 and def2, initially, are lists in which each separate element is a word. 即def1和def2最初是列表,其中每个单独的元素都是一个单词。 I can't check if these lists are being populated by printing them because the indexoutofboundsexception pops at the very moment the loop starts. 我无法通过打印它们来检查是否填充了这些列表,因为indexoutofboundsexception在循环开始的那一刻就会弹出。 However, I do print the values of the sizes of mdef, def1.size() and def2.size(), and the values turn out to be 13, or 15, showing that no list is empty before the "for" loop starts. 但是,我确实打印了mdef,def1.size()和def2.size()的大小值,结果变成13或15,显示在“ for”循环开始之前没有列表为空。 。

The mdef++ was something I added recently, not to exactly to solve this specific problem, but the error has been popping since before I added the mdef++ part. 我最近添加了mdef ++,并不是为了完全解决这个特定问题,但是自从我添加mdef ++部分之前,该错误一直在弹出。 As I explained, The intention is to increase mdef++ when the shortest list is extended (but only when the short list is extended) so we iterate through all the words of the short list, and not more. 正如我所解释的那样,目的是在扩展最短列表时(但仅在扩展短列表时)增加mdef ++,以便我们遍历短列表的所有单词,而不是更多。

One issue with your code is that when you increment mdef you do not check to see if it now exceeds the length of the other list. 代码的一个问题是,当您增加mdef时,不会检查它现在是否超过另一个列表的长度。

For example, suppose def1 had 3 words and def2 had 4 words. 例如,假设def1有3个单词,而def2有4个单词。 mdef would start at 3. But then suppose you successively add two spaces to def1 and increment mdef twice to be 5. This now exceeds the length of def2 and will then cause an index out of bounds exception in the def2 else condition if you keep iterating up to 5. mdef将从3开始。但是然后假设您连续向def1添加两个空格,并将mdef两次递增为5。这现在超过了def2的长度,并且如果您继续进行迭代, def2def2 else条件中导致索引超出范围异常最多5。


Added later: 稍后添加:

Another serious issue with your code (that I thought of later) is that when you add the space to a list (either def1 or def2 ) this shifts the indices of all of the subsequent elements up by 1. So, for example, if you add a space at spot 0 in def1 when i is 0, then on the next pass through the loop, having incremented i to 1, you will look at the same word in def1 that you looked at in the previous pass. 代码的另一个严重问题(我稍后会想到)是,当您将空间添加到列表( def1def2 )时,这会将所有后续元素的索引上移1。因此,例如,如果您当i为0时,在def1点0处添加一个空格,然后在下一次遍历循环时,将i递增到1,您将看到与上def1相同的def1中的单词。 This is probably the source of some of your exceptions (as it would lead to a continual loop until you exceed the length of the other list: problem #1 above). 这可能是某些异常的根源(因为这会导致连续循环,直到您超过另一个列表的长度为止:上述问题1)。


To correct both of these issues, you would need to change your code to something like: 要更正这两个问题,您需要将代码更改为以下内容:

int i = 0;
int j = 0;
while (i < def1.size()  &&  j < def2.size()) {
    if (stopList.contains(def1.get(i)) && !stopList.contains(def2.get(j)))
        def2.add(j++, " ");
    else if (stopList.contains(def2.get(j)) && !stopList.contains(def1.get(i)))
        def1.add(i++, " ");
    ++i;
    ++j;
}

Note that you don't ned mdef any more in this implementation. 请注意,在此实现中不再需要mdef

Man, I think I got it. 伙计,我想我明白了。 I modified the code, but I hope you understand what I did: 我修改了代码,但是希望您能理解我所做的事情:

static public void main(String[] argv) {
    String[] sList = "of a in to under".split(" ");
    String[] definition1 = "Free fall descent of a body subjected only to the action of gravity"
            .split(" ");
    String[] definition2 = "Free fall movement of a body in a gravitational field under the influence of gravity"
            .split(" ");
    List<String> def1 = new ArrayList<String>();
    List<String> def2 = new ArrayList<String>();
    List<String> stopList = new ArrayList<String>();

    for (String word : definition1) {
        def1.add(word);
    }
    for (String word : definition2) {
        def2.add(word);
    }
    for (String word : sList) {
        stopList.add(word);
    }

    int mdef = (def1.size() <= def2.size()) ? def1.size() : def2.size(); // Shortest
                                                                            // length

    for (int i = 0; i < mdef; i++) {
        System.out.println(i);
        if (!stopList.contains(def1.get(i)) && !stopList.contains(def2.get(i))) {
            continue;
        }

        else if (stopList.contains(def1.get(i)) && stopList.contains(def2.get(i))) {
            continue;
        }

        else if (!stopList.contains(def1.get(i)) && stopList.contains(def2.get(i))) {
            def1.add(i, " ");
            mdef = (def1.size() <= def2.size()) ? def1.size() : def2.size(); // define mdef again
        }

        else if (stopList.contains(def1.get(i)) && !stopList.contains(def2.get(i))) {
            def2.add(i, " ");
            mdef = (def1.size() <= def2.size()) ? def1.size() : def2.size(); // define mdef again
        }

    }

    for (String word : def1) {

        if (word.equals(" "))
            System.out.print("_ ");
        else
            System.out.print(word+" ");
    }

    System.out.println();

    for (String word : def2) {
        if (word.equals(" "))
            System.out.print("_ ");
        else
            System.out.print(word+" ");
    }           
}

Is this the exact code you're using? 这是您使用的确切代码吗? I just ran it and it worked fine, I used: 我只是运行它,它工作正常,我使用了:

import java.util.*;

public class HelloWorld {

    public static void main(String []args) {
        String stoplist= "of a in to and under";
        String defA1 = "Free fall descent  of a body subjected only to            the   action of  gravity";
        String defA2 = "Free fall movement of a body in        a    gravitational field under  the influence of gravity";

        String[] sList = stoplist.split(" ");  //this is the stoplist
        String[] definition1 = defA1.split(" ");  //this is the array of words of the first definition
        String[] definition2 = defA2.split(" ");  //this is the array of words of the second definition
        List<String> def1 = new ArrayList<String>();
        List<String> def2 = new ArrayList<String>();
        List<String> stopList = new ArrayList<String>();

        for (String word : definition1) {
            def1.add(word); //I transform arrays into lists this way because I used to think that using .asList() was the problem.
        }
        for (String word : definition2) {
            def2.add(word);
        }
        for (String word : sList) {
            stopList.add(word);
        }

        int mdef = (def1.size() <= def2.size()) ? def1.size() : def2.size(); //here mdef will have the value of the lenght of the shortest definition, and we are going to use the value of mdef to iterate later on.

        for (int i = 0; i < mdef; i++) {
            if (stopList.contains(def1.get(i))) {  //here I check if the first word of the first definition is also found in the stoplist.
                if (!stopList.contains(def2.get(i))) {  //If the word of def1 previously checked is in the stoplist, as well as the corresponding word in the second definition, then we won't add a " "(blank) space in the corresponding position of the second definition.
                    def2.add(i , " "); //here I add that blank space, only if the stoplist word in def1 corresponds to a non-stoplist word in def2. Again, we do this so the stoplist word in def1 corresponds to a blank space OR another stoplist word in def2.
                    if (mdef == def2.size())
                        mdef++; //In case the shortest definition is the definition to which we just added spaces, we increment mdef++, because that space added increases the length of the shortest definition, and to iterate in this recenlty extended definiton, we have to increment the index with which we iterate.
                }
            } else if (stopList.contains(def2.get(i))) { //this else if does the same than the previous one, but checks for the second definition instead of the first one. And adds blanks to def1 instead of def2 if necessary.
                if (!stopList.contains(def1.get(i))) {
                    def1.add(i , " ");
                    if (mdef == def1.size())
                        mdef++;
                }
            }
        }

        for (String word : def1) {
            System.out.print(word+",");
        }

        System.out.println();

        for (String word : def2) {
            System.out.print(word+",");
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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