我执行列表操作时出现异常

时间:2015-03-26 14:58:36

标签: java list exception-handling

我有以下课程

我在监视一个队列。当一条消息入队时我会记录它,当消息出列时也是如此。这段代码适用于75%的纠正。有时文件会被排队太多,但这不是主要的问题。

现在让我们看看下面的代码,首先我与队列建立连接,而不是在我排队队列时将消息ID添加到我的列表中。如果列表大于队列大小(我每次循环时都计算它),则需要发生出队。帮助列表首先复制arraylist并删除它在队列中遇到的所有项目。它没有遇到的项目来自队列,所以他们需要从列表中出队。如果列表不大,我会检查id是否已经在列表中,如果不是,我会进行新的排队。

package queueFeed;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;

import javax.jms.Message;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Logger;

public class QueueRunner {
    private static Logger log = Logger.getLogger(QueueRunner.class.getName());



    public void run() throws Exception {

        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin","admin","tcp://localhost:61616");
        javax.jms.Connection connection =  factory.createConnection();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        QueueBrowser browser = session.createBrowser(new ActiveMQQueue("KBC"));

        List<String> ids = new ArrayList<>();
        int queueSize = 0;
        int counter = 0;
        connection.start();
        while(true) {

        Enumeration enumeration = browser.getEnumeration();
            if(queueSize < ids.size())
            {
                List<String> checkList = ids;
                while(enumeration.hasMoreElements()){
                    Message message = (Message) enumeration.nextElement();
                    checkList.remove(message.getJMSMessageID());
                    counter++;
                }

                if(checkList.size() > 0 && ids.size() > 0)
                for(String notEncountered : checkList) {
                    ids.remove(notEncountered);
                    System.out.println("dequeued " + notEncountered);
                }
                queueSize = counter;
                counter = 0;
            }
            else {

                while(enumeration.hasMoreElements()){
                    counter++;
                Message message = (Message) enumeration.nextElement();
                String id = message.getJMSMessageID();
                if (!ids.contains(id)) {
                    ids.add(id);
                    System.out.println("enqueued message" + message.getJMSMessageID());
                    Thread.sleep(1000);
                }
            }
                queueSize = counter;
        counter = 0;
    }
}}}

当我出队时,我得到以下错误:

 Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
    at java.util.ArrayList$Itr.next(ArrayList.java:831)
    at queueFeed.QueueRunner.run(QueueRunner.java:43)
    at dashboard.Main.main(Main.java:34)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

错误指向第43行,即for(String notEncountered:helpList)行...出了什么问题?

3 个答案:

答案 0 :(得分:1)

如果要在循环中修改List,则必须

创建您运行的临时列表:

List<Integer> tmpList = copyOf(myList);

for(int n : tmpList){
    if(myList.contains(n) && SomethingIsTrue()){
        myList.remove(n);
    }
}

或者您必须在列表中向后运行

for(int i = myList.size()-1; i >= 0; i--){
    if(SomethingIsTrue()){
        myList.remove(i);
    }
}

注意这是伪代码(有一些检查方法等)

在List上运行并修改它,在删除其他项时更改其项目的索引。这就是为什么你得到ConcurrentModificationException

在你的例子中,你说:

List<String> checkList = ids;

所以checkListids是平等的。如果您从ids删除某些内容,但在checkList上运行,则仍会在同一对象上运行。您必须创建ids列表的副本才能获得临时行为。

答案 1 :(得分:0)

您无法使用基于范围的循环删除项目。使用迭代器。

Iterator<String> it = ids.iterator();
while(it.hasNext){
    if(checkList.contains(it.next()) it.remove();
}

而不是

for(String notEncountered : checkList) {
                    ids.remove(notEncountered);
                    System.out.println("dequeued " + notEncountered);
                }

答案 2 :(得分:-2)

在正常的for循环中,无法从列表中删除项目。 你需要使用迭代器来进行这种表演。

您可以通过

替换正常的for循环
if(checkList.size() > 0 && ids.size() > 0)
                {
                    Iterator<String> iterator = checkList.iterator();
                    while(iterator.hasNext()) {
                        String messageId = iterator.next();
                        System.out.println("dequeued message "+ messageId);
                        iterator.remove();
                    }
                }

这可以解决您的问题。