Iterator isEmpty()调用导致noSuchElementexception?

时间:2012-10-24 16:10:08

标签: java android iterator hashmap

我目前有以下代码

while (!visibleTiles.isEmpty())) {
    tile = visibleTiles.keySet().iterator().next();
    if (tile != null){
        bitmap = visibleTiles.remove(tile);
        if(bitmap != null && !containsKey(tile)){ //safe to recycle if tile cache is not actively holding it
            bitmap.recycle();
        }
    }
}

但是,我在行

上遇到NoSuchElementException崩溃
tile = visibleTiles.keySet().iterator().next();

使用isEmpty()方法并调用hasNext()调用有很大的不同吗?我知道hashmaps没有hasNext()调用,所以我做了以下内容:

while (visibleTiles.keySet().iterator().hasNext()) {
    tile = visibleTiles.keySet().iterator().next();
    if (tile != null){
        bitmap = visibleTiles.remove(tile);
        if(bitmap != null && !containsKey(tile)){ //safe to recycle if tile cache is not actively holding it
            bitmap.recycle();
        }
    }
}

显然,我知道我应该运行应用程序并查看它是否崩溃,但问题是重现问题很困难。

谢谢!

6 个答案:

答案 0 :(得分:4)

visibleTiles.isEmpty()

只检查地图是否为空(或)是否有任何元素。

ile = visibleTiles.keySet().iterator().next();

从迭代器中检索下一个元素。

在迭代器上执行hasNext()之前,您需要进行next()检查。

hasNext() javadoc

  

如果迭代有更多元素,则返回true。 (换一种说法,   如果next会返回一个元素而不是抛出一个元素,则返回true   异常。)

所以,如果没有可用的元素,并且在迭代器上调用next()将返回NoSuchElementException

除此之外,我认为你真的不想空检查

while (!visibleTiles.isEmpty())) {
....
}

答案 1 :(得分:1)

每次调用*时,

while (visibleTiles.keySet().iterator().hasNext())都会创建一个新的Iterator。如果visibleTiles不为空,则总是如此,因为从不调用相应迭代器的下一个方法,并且内部指针永远不会前进。

迭代器应该像这样使用:

Iterator<TileType> tileIt = visibleTiles.keySet().iterator();
while (tileIt.hasNext()) {
    TileType tile = tileIt.next();
    // ...
}

*这里的要点是可能有几个迭代器同时引用同一个集合。每个迭代器都有自己的内部状态存储(不一定是显式的)最后返回的元素,然后由next()调用返回。这可能很有用,例如,对集合中的所有元素对执行一些操作,其中需要两个迭代器。

答案 2 :(得分:1)

您可以使用com.google.common.collect.Iterables类对Iterable值进行空检查。

Iterables.isEmpty(yourIterable)

答案 3 :(得分:0)

在条件解决问题时进行修复

通过在前面添加not(!)来更改条件以检查不为空:

   while (!visibleTiles.isEmpty())) {

编辑:示例代码:

    HashMap<String, Object> visibleTiles = new HashMap<String, Object>();
    visibleTiles.put("abc", new Object());
    visibleTiles.put("xyz", new Object());
    visibleTiles.put("def", new Object());
    String tile = null;
    while (!visibleTiles.isEmpty()) {
        tile = visibleTiles.keySet().iterator().next();
        if (tile != null){
            Object bitmap = visibleTiles.remove(tile);
            if(bitmap != null){ //safe to recycle if tile cache is not actively holding it
                System.out.println("Recycle");
            }
        }
    }

答案 4 :(得分:0)

这与您提出的问题无关(已经回答),但仅作为docs

的旁注
  

请注意,迭代器的快速失败行为无法得到保证,因为一般来说,在存在非同步并发修改的情况下,不可能做出任何硬性保证。失败快速迭代器会尽最大努力抛出ConcurrentModificationException。因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的快速失败行为应该仅用于检测错误。

你可以避免你可以在keyset迭代器上删除(最终从地图中删除条目),而不是在地图上进行删除(在迭代键集时从外部修改地图)。

代码中看起来容易受到攻击的部分:

tile = visibleTiles.keySet().iterator().next();
if (tile != null){
    bitmap = visibleTiles.remove(tile);

示例:

以下结果为ConcurrentModificationException

Map<String, String> map = new HashMap<String, String>();         
map.put("1", "1");
map.put("2", "1");
map.put("3", "1");
Iterator<String> it = map.keySet().iterator();
while(it.hasNext()) {
    if(it.next().equals("2")) {
         map.remove("2");
    }
}

以下内容从地图中删除条目:

Map<String, String> map = new HashMap<String, String>();         
map.put("1", "1");
map.put("2", "1");
map.put("3", "1");
Iterator<String> it = map.keySet().iterator();

while(it.hasNext()) {

    String key = it.next();

    if(key != null) {

         String value = map.get(key); // you have the value and
         it.remove(); //you are modifying the map only through the iterator itself

         //... do stuffs with the value
    }
}

答案 5 :(得分:0)

由于有关效率的良好信息,我通过删除isEmpty调用修复了原始帖子中的代码没有这样的元素异常。看起来你通常想在同一个代码区域中调用next时使用hasNext。

while (visibleTiles.keySet().iterator().hasNext()) {
    tile = visibleTiles.keySet().iterator().next();
        if (tile != null){
            bitmap = visibleTiles.remove(tile);
            if(bitmap != null && !containsKey(tile)){ //safe to recycle if tile cache is not actively holding it
                bitmap.recycle();
            }
        }
    }