我在下面的StackOverflowError中发现了一个奇怪的随机错误。这不是确定性的,所以我很难捕获这个问题......我有一个Arraylist,它被包装到Collections :: unmodifiableList(...),然后使用for进行迭代(Val val :myValues)
这怎么可能?集合中的UnmodifiableList实现中的字段都是最终的,因此不能存在任何循环依赖(例如A-> B-> A))。不,这里也不涉及反思......
java.lang.StackOverflowError
at java.util.Collections$UnmodifiableCollection$1.<init>(Collections.java:1064)
at java.util.Collections$UnmodifiableCollection.iterator(Collections.java:1063)
at java.util.Collections$UnmodifiableCollection$1.<init>(Collections.java:1064)
at java.util.Collections$UnmodifiableCollection.iterator(Collections.java:1063)
at java.util.Collections$UnmodifiableCollection$1.<init>(Collections.java:1064)
at java.util.Collections$UnmodifiableCollection.iterator(Collections.java:1063)
at java.util.Collections$UnmodifiableCollection$1.<init>(Collections.java:1064)
at java.util.Collections$UnmodifiableCollection.iterator(Collections.java:1063)
at java.util.Collections$UnmodifiableCollection$1.<init>(Collections.java:1064)
at com.server.ServerFunction$ServerFunctionResult.evaluateValues(ServerFunctionn.java:562)
at com.server.ServerFunction$ServerFunctionResult.access$300(ServerFunctionn.java:348)
at com.server.ServerFunction.perform(ServerFunction.java:1171)
生成此代码的代码(由于我无法在此处发布实际代码,因此已重新编写代码...):
public final static class ServerFunctionResult
{
private final List<String> myValues;
private final boolean myIsProcessed;
public ServerFunctionResult(List<String> values, boolean isProcessed)
{
// Reduce object retention of empty list objects
myValues = values.isEmpty() ? Collections.EMPTY_LIST : Collections.unmodifiableList(values);
myIsProcessed = isProcessed;
}
public ServerFunctionResult evaluateValues()
{
if (!myIsProcessed)
{
for (String s : myValues) // <-- HERE IT THROWS
{
// Process values
}
return new ServerFunctionResult(myValues, true);
}
return this;
}
}
这是Java 7u51。我试图绕过这个问题,但现在我怀疑是JVM错误......
这个问题对其他人来说是否熟悉?
答案 0 :(得分:2)
以下是来自Java 7u40的UnmodifiableCollection
类的代码:
static class UnmodifiableCollection<E>
implements Collection<E>, Serializable {
private static final long serialVersionUID = 1820017752578914078L;
final Collection<? extends E> c;
UnmodifiableCollection(Collection<? extends E> c) {
if (c==null)
throw new NullPointerException();
this.c = c;
}
....
public Iterator<E> iterator() {
return new Iterator<E>() {
private final Iterator<? extends E> i = c.iterator();
public boolean hasNext() {return i.hasNext();}
public E next() {return i.next();}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
(您应该在JDK for Java 7u51中拥有实际的源代码。)
如您所见,当您在不可修改的集合上调用iterator
时,它会在匿名类上创建一个实例。该类的构造函数调用c.iterator()
...其中c
是包装类。但是,堆栈跟踪意味着c
本身就是一个不可修改的集合。
我能想出一个似是而非的解释:
还有其他可能的解释涉及使用反射(或字节码工程)来打破类型抽象边界,或者假设的JVM(可能是JIT编译器)错误。坦率地说,JVM错误解释是相当难以置信的,但如果我怀疑我会从升级到最新的Java 7版本开始。 (实际上,我可能会这样做!7u51在Java 7平台上缺少1年的安全补丁和错误修复。)