Java 为什么在按需填充的集合上迭代器为空?
我有以下代码:Java 为什么在按需填充的集合上迭代器为空?,java,tomcat,iterator,Java,Tomcat,Iterator,我有以下代码: for (String helpId : helpTipFragCache.getKeys()) { List<HelpTopicFrag> value = helpTipFragCache.getValue(helpId); helpTipFrags.put(helpId, value); } for(字符串helpId:helpTipFragCache.getKeys()) { 列表值=helpTipFragCache.getValue(help
for (String helpId : helpTipFragCache.getKeys())
{
List<HelpTopicFrag> value = helpTipFragCache.getValue(helpId);
helpTipFrags.put(helpId, value);
}
for(字符串helpId:helpTipFragCache.getKeys())
{
列表值=helpTipFragCache.getValue(helpId);
helpTipFrags.put(helpId,value);
}
helpTipFragCache有一种机制,可以在缓存为空时加载该缓存。getKeys()方法将触发此操作,并在调用此操作时加载缓存。然而在上面的例子中,我看到了不同的行为
我首先快速调试了它,以查看缓存是否确实在填充(在eclipse中)。我进行了一步,但从未输入for循环(由于迭代器为空)
然后我再次调试了它(使用相同的代码),进入getKeys()并分析了整个过程。然后它做了它应该做的一切,迭代器有值要迭代,控制台中有和平
我已通过更改代码来解决此问题:
Set<String> helpIds = helpTipFragCache.getKeys();
helpIds = helpTipFragCache.getKeys();
for (String helpId : helpIds)
{
List<HelpTopicFrag> value = helpTipFragCache.getValue(helpId);
helpTipFrags.put(helpId, value);
}
Set helpIds=helpTipFragCache.getKeys();
helpIds=helpTipFragCache.getKeys();
用于(字符串helpId:helpId)
{
列表值=helpTipFragCache.getValue(helpId);
helpTipFrags.put(helpId,value);
}
很明显,调试触发了某些东西的初始化或不同的行为,有人知道是什么原因导致了这种情况吗?基本上,从返回的集合创建迭代器时发生了什么
其他一些相关信息:
- 此代码在服务器启动时执行(tomcat)
- 当从包含的jar中执行时,此代码的行为与预期不符,但当它位于同一代码库中时,会发生这种情况
- 收藏是一套
public Set<String> getKeys() throws Exception
{
if (CACHE_TYPE.LOAD_ALL == cacheType)
{
//Fake a getValue call to make sure the cache is loaded
getValue("");
}
return Collections.unmodifiableSet(cache.keySet());
}
public final T getValue(String key, Object... singleValueArgs) throws Exception
{
T retVal = null;
if (notCaching())
{
if (cacheType == CACHE_TYPE.MODIFY_EXISTING_CACHE_AS_YOU_GO)
{
retVal = getSingleValue(key, null, singleValueArgs);
}
else
{
retVal = getSingleValue(key, singleValueArgs);
}
}
else
{
synchronized (cache)
{
if (needToLoadCache())
{
logger.debug("Need to load cache: " + getCacheName());
if (cacheType != CACHE_TYPE.MODIFY_EXISTING_CACHE_AS_YOU_GO)
{
Map<String, T> newCache = null;
if (cacheType != CACHE_TYPE.MODIFY_EXISTING_CACHE)
{
newCache = getNewCache();
}
else
{
newCache = cache;
}
loadCache(newCache);
cache = newCache;
}
lastUpdatedInMillis = System.currentTimeMillis();
forceLoadCache = false;
}
}
...//code in here does not execute for this example, simply gets a value that is already in the cache
}
return retVal;
}
public Set getKeys()引发异常
{
if(CACHE\u TYPE.LOAD\u ALL==cacheType)
{
//伪造getValue调用以确保缓存已加载
getValue(“”);
}
返回集合.unmodifiableSet(cache.keySet());
}
公共最终T getValue(字符串键、对象…singleValueArgs)引发异常
{
T retVal=null;
if(notCaching())
{
if(cacheType==CACHE\u TYPE.修改现有的
{
retVal=getSingleValue(key,null,singleValueArgs);
}
其他的
{
retVal=getSingleValue(键,singleValueArgs);
}
}
其他的
{
已同步(缓存)
{
if(needToLoadCache())
{
debug(“需要加载缓存:+getCacheName());
if(cacheType!=缓存类型。修改现有的缓存)
{
Map newCache=null;
if(cacheType!=缓存类型。修改现有缓存)
{
newCache=getNewCache();
}
其他的
{
newCache=cache;
}
loadCache(newCache);
cache=newCache;
}
LastUpdatedMillis=System.currentTimeMillis();
forceLoadCache=false;
}
}
…//此处的代码不针对本例执行,只获取缓存中已有的值
}
返回返回;
}
并返回到原始类(以前的代码发布自该类):
@覆盖
受保护的void加载缓存(
映射(新缓存)
抛出异常
{
Map _helpTipFrags=helpDAO.getHelpTopicFrags(getAppName(),_searchid);
添加DisplayModeToFrags(\u helpTipFrags);
newCache.putAll(_helpTipFrags);
}
在上面,进行数据库调用以获取要放入缓存的值。的答案
基本上,从返回的集合创建迭代器时会发生什么情况?
案例中的for
循环将Set
视为,并使用通过调用获取的
基本相当于
Set as = ...;
Iterator hidden = as.iterator ();
while (hidden.hasNext ()) {
a = hidden.next ();
doSth ();
}
@蒂莫,这里不会发生这种事。OP将元素放入一个不同的集合中,而不是迭代的集合。@millimoose哦,你说得对。对不起,如果不知道缓存是如何实现的,我不确定这是否应该负责。没有任何一个普遍适用的原因可以解释为什么在调试时会有不同的行为。调试器可能会调用一些方法(如
.size()
),而您的代码不会调用这些方法来生成调试输出,并且此方法会导致缓存被填充,而getKeys()
则不会。(或者说,这辆马车需要叫两遍。)@millimoose这真的很重要吗?迭代器应该使用循环中给定的集合。getKeys方法解析为一个填充的集合,但迭代器正在抢先一步。不管怎样,我更新了这个问题。@Noremac这可能很重要,因为迭代器在不喜欢的情况下随机不迭代集合,这是一种先验的可能性。更可能的解释是,在某些条件下,您正在空集合上创建迭代器。-1:我不知道这如何解决OP的问题。他不是要解释增强的for循环是如何工作的,而是为什么他的(未知)缓存实现有缺陷。\@millimoose实际上他是在问基本上,从返回的集合创建迭代器时发生了什么?
。那么为什么要投反对票呢?因为我不同意你对这个问题的理解——你所关注的子问题显然不是问题的原因。(问题中的“坏的”和“工作的”片段最终都调用了相同的iterator()
实现。)我认为这使得你的答案毫无帮助。@millimose子问题仍然是原始问题的一部分。@millimose尽管如此,我还是问了这个问题,回答是对我原始问题的贡献,尽管可能还有另一个原因。
Set as = ...;
for (A a : as) {
doSth ();
}
Set as = ...;
Iterator hidden = as.iterator ();
while (hidden.hasNext ()) {
a = hidden.next ();
doSth ();
}