3

私は現在次のコードを持っています

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()呼び出しの呼び出しに大きな違いはありますか?ハッシュマップには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();
        }
    }
}

もちろん、アプリを実行してクラッシュするかどうかを確認するだけでよいことはわかっていますが、問題の再現が難しいという問題があります。

ありがとう!

4

6 に答える 6

6

visibleTiles.isEmpty()

マップが空であるかどうか(またはマップに要素があるかどうか)をチェックするだけです。

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

イテレータから次の要素を取得します。

イテレータでhasNext()行う前にチェックを行う必要があります。next()

hasNext() javadocによると

反復にさらに要素がある場合はtrueを返します。(つまり、nextが例外をスローするのではなく要素を返す場合はtrueを返します。)

したがって、使用可能な要素がなく、next()イテレータを呼び出すと、が返されますNoSuchElementException

それに加えて、あなたは本当に空のチェックをしたくないと思います

while (!visibleTiles.isEmpty())) {
....
}
于 2012-10-24T16:12:41.503 に答える
1

while (visibleTiles.keySet().iterator().hasNext())Iterator呼び出されるたびに新しいものを作成します*。空でない場合、それぞれのイテレータの次のメソッドが呼び出されることはなく、内部ポインタが進むこともないvisibleTilesため、これは常にtrueになります。

イテレータは次のように使用する必要があります。

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

*ここでのポイントは、同じコレクションを同時に参照する複数のイテレータが存在する可能性があるということです。各イテレータには、どの要素が最後に返され、どの要素が呼び出しによって次に返されるかを(必ずしも明示的にではなく)格納する独自の内部状態がありnext()ます。これは、たとえば、2つのイテレータが必要なコレクションの要素のすべてのペアに対して何らかの操作を実行する場合に役立ちます。

于 2012-10-24T16:27:47.733 に答える
1

com.google.common.collect.Iterablesクラスを使用して、Iterable値の空のチェックを行うことができます。

Iterables.isEmpty(yourIterable)
于 2017-11-01T08:00:56.183 に答える
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();
            }
        }
    }
于 2012-10-25T17:38:25.393 に答える
0

while条件を修正すると、問題が解決するはずです。

前に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");
            }
        }
    }
于 2012-10-24T16:28:32.137 に答える
0

これは、あなたが尋ねている質問(すでに回答済み)とは関係ありませんが、ドキュメントからの補足としてだけです。

イテレータのフェイルファスト動作は保証できないことに注意してください。一般的に言えば、同期されていない同時変更が存在する場合、ハード保証を行うことは不可能です。フェイルファストイテレータは、ベストエフォートベースでConcurrentModificationExceptionをスローします。したがって、その正確性をこの例外に依存するプログラムを作成するのは誤りです。イテレータのフェイルファスト動作は、バグを検出するためにのみ使用する必要があります。

マップ自体で削除を実行する(キーセットを反復処理している間にマップを外部で変更する)代わりに、キーセットイテレーターで削除(最終的にはマップからエントリを削除)することを回避できます。

脆弱に見えるコードの部分:

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
    }
}
于 2012-10-24T16:39:19.663 に答える