我的结构是:
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);
}
}
答案 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时,它会爆炸,你会在日志中看到异常并且能够看到是谁检查了栈跟踪。
要清楚,列表中的对象“成为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