如何跟踪ArrayList中的对象变为null?

时间:2011-07-02 15:05:26

标签: java arraylist

我的结构是:

Map<String, ArrayList<Bean>>

此Arraylist从不同线程内的不同位置进行修改(添加/删除)。

有时,ArrayList内的某些bean正在变为null。如何跟踪它何时变为空?我想跟踪什么使bean为null,以修复bug。

当使用庞大的数据集测试场景时会发生这种情况。

以下是失败的确切代码:

for (int i = 0; i < eventlogs.size(); i++) {
    MessageEventLogBean msgEventLogBean = (MessageEventLogBean) eventlogs.get(i);
    eventlogs.remove(i); 
    try {
        logWriter.write(msgEventLogBean, context);
    } catch (FusionException e) {
        logger.error("Error While writing the event log bean ", e);
    }
}

3 个答案:

答案 0 :(得分:2)

使用一个覆盖add方法的匿名类,而不是标准列表实现,并添加特殊代码来检查添加的对象是否为null,如下所示:

    List<T> list = new ArrayList<T>() {
        public boolean add(T e) {
            if (e == null) {
                throw new NullPointerException("Attempt to add null to list");
            }
            return super.add(e);
        }
    };

您应该同样覆盖所有“添加”方法以确保。当代码添加一个null时,它会爆炸,你会在日志中看到异常并且能够看到是谁检查了栈跟踪。

EDITED

要清楚,列表中的对象“成为null不可能。您可以添加 null,或者您可以从列表中删除对象,但列表中的对象将保留直到被移除。

要明确的是,null进入列表的唯一方式是将其放在那里 - 即通过add()方法之一添加它或者addAll()方法。并发修改问题导致此问题(您可能会获得ConcurrentModificationException,但仍然不会在其中放置null

代码如

Object o = list.get(1);
o = null;

无效,因为您只是对对象的引用的副本进行了归零 - list仍然是对象的引用。

但是,根据Bean对象的设计,它们可能是可变的。虽然对Bean对象的引用将保持不变,但是对于 Bean中的某些字段可能成为null。要理解这一点,你需要在给定null参数时对setter进行编码,或者通过重写类,或者通过匿名类重载setter(类似于我上面的初步建议)。 / p>

答案 1 :(得分:0)

这有点工作,但您可以创建自己的List接口实现,将所有方法委托给ArrayList。在您通常会返回ArrayList的访问器方法中,而是返回包含在其中的ArrayList的调试实现。然后只需在set方法上设置一个断点,你就会确切地知道在ArrayList上调用了什么代码。

答案 2 :(得分:0)

也许这就是你的意图

private final Queue<MessageEventLogBean> eventlogs = new ConcurrentLinkedQueue<>();

// this loop stops when it runs out of objects.
MessageEventLogBean msgEventLogBean;
while ((msgEventLogBean = eventlogs.poll()) != null) {
    try {
        logWriter.write(msgEventLogBean, context);
    } catch (FusionException e) {
        logger.error("Error While writing the event log bean ", e);
    }
}

// this loops until the thread is interrupted
private final BlockingQueue<MessageEventLogBean> eventlogs = new LinkedBlockingQueue<>();

while (true) {
    MessageEventLogBean msgEventLogBean = eventlogs.take();
    try {
        logWriter.write(msgEventLogBean, context);
    } catch (FusionException e) {
        logger.error("Error While writing the event log bean ", e);
    }
}

这两个选项都是线程安全的。


您可以覆盖列表的add()和set()方法,以使null无效并引发异常。

List<MyType> list = new ArrayList<MyType>() {
    public boolean add(MyType mt) {
        if(mt == null) throw new IllegalArgumentException();
        super.add(mt);
    }
};

考虑以下代码

String a = "hi"; // a => "hi"
String b = a; // a => "hi" and b => "hi"
a = null; // a => null and b => "hi"

String a是对String的引用,当您为其分配null时,您只更改a的值,并且对同一对象的其他引用不受影响。


处理每个第二个条目的方法,或者为什么使用remove(i)不太可能是你想要的。

List<Integer> list = new ArrayList<>();
for(int i=0;i<10;i++) list.add(i);
for(int i=0;i<list.size();i++) {
    System.out.println(list.get(i));
    list.remove(i);
}

打印

0
2
4
6
8