为什么迭代器在按需填充的集合上为空?

时间:2012-11-15 21:31:26

标签: java tomcat iterator

我有以下代码:

for (String helpId : helpTipFragCache.getKeys())
{
    List<HelpTopicFrag> value = 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);
}

显然,调试触发了初始化或行为不同的事情,是否有人知道是什么导致这种情况?基本上,从返回的集合创建迭代器会发生什么?

其他一些相关信息:

  • 此代码在服务器启动时执行(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;
}

然后回到原来的类(从前面的代码发布的地方):

    @Override
    protected void loadCache(
            Map<String, List<HelpTopicFrag>>    newCache)
    throws Exception
    {
        Map<String, List<HelpTopicFrag>> _helpTipFrags = helpDAO.getHelpTopicFrags(getAppName(), _searchIds);
        addDisplayModeToFrags(_helpTipFrags);
        newCache.putAll(_helpTipFrags);
    }

在上面,进行数据库调用以获取要放入缓存的值。

1 个答案:

答案 0 :(得分:0)

答案

Basically, what is happening to create the iterator from the returned collection?

您的案例中的for循环将Set视为Iterable,并使用通过调用Iterator获得的Iterable.iterator()

Set as = ...;

for (A a : as) {
    doSth ();
}

基本等同于

Set as = ...;

Iterator hidden = as.iterator ();
while (hidden.hasNext ()) {
    a = hidden.next ();
    doSth ();
}