2017-01-17 4 views
1

反復ごとに新しいオブジェクトを作成しないEnumMapを反復処理する方法はありますか?エントリセットのイテレータは毎回新しいエントリを返します。私が見ることができる唯一の方法は、あなたのコードではありません、反復ごとに新しいオブジェクトを作成しないEnumMapを反復する

for(K k: map.keySet()) 
    foo(k, map.get(k)); 

が、これは

public Map.Entry<K,V> next() { 
     if (!hasNext()) 
      throw new NoSuchElementException(); 
     lastReturnedEntry = new Entry(index++); 
     return lastReturnedEntry; 
    } 
+0

あなた自身の解決策は何が悪いですか? – RealSkeptic

+1

'for(V value:map.values())foo(value);'はどうでしょうか?値を取得する以外の目的でキーを使用しているようではありません。 – VGR

+0

@VGRフェアポイント。私はキーも必要です。 – hawk

答えて

2

まず、イテレータが2つのオブジェクトのタプルを返すように思っているようです。

Javaでは、これを実行する唯一の方法は、別のオブジェクトにそれらをラップすることです。 (書いている時点では、そうです。)イテレータは、キーと値以外のオブジェクトを返さなければなりません。そのオブジェクトは、next()への呼び出しが返される前に、ある時点で作成されなければなりません。

  1. put()にこのエントリオブジェクトを作成します。このことを念頭に置いて、制約付き

    は取るには3つのもっともらしいパスがあります。

  2. entrySet()の最初の繰り返しでエントリオブジェクトを作成します(後でキャッシュします)。
  3. entrySet()のすべての反復で新しいエントリオブジェクトを作成します。

組み込みのEnumMapは、実装が最も簡単であり、エントリを反復処理する必要がない場合に最も経済的な解決策であるという理由で、オプション3になりました。欠点は、複数回反復する必要がある場合は、他のソリューションより多くのオブジェクトを作成することです。

オプション1は実装が簡単ですが、アクセスするつもりがない場合でも、マップにエントリを追加するたびに明白なオーバーヘッドがあります。

最後に、オプション2では、コードの複雑さがわずかに増加し、反復処理と要素の追加を繰り返す際にいくつかのエッジケースが発生しますが、理論的には最高のメモリプロファイルが得られます。

複数の繰り返しのメモリオーバーヘッドがアプリケーションで問題であることが判明した場合は、オプション2を簡単に実装できますが、ほとんどの場合、その違いが目立つのではないでしょうか。

p.s.:あなたが慣用的な解決法から逸脱し、わずかに狂った領域に入る場合は、同じMap.Entryインスタンスをすべてのエントリに再利用することができます。これは明らかにMap.Entryから期待されるものと矛盾しますが、メモリ割り当てのオーバーヘッドが最小限に抑えられ、簡単な反復シナリオでそれを取り除くことができます。あなたがより速い最終製品で終わるかどうかは誰でも推測されます、あなたはそれを測定する必要があります。

0

まずそののentrySet上で、次のイテレータの実装を持っているEnumMapについて、具体的で明確にするためであるたびにオブジェクトを作成できませ。既存のオブジェクトにの参照しか得られません。

for (Map.Entry<K, V> entry : map.entrySet()) { 
    // use entry.getKey() and entry.getValue() 
} 

またはJava 8バージョン:

map.forEach((k, v) -> {...}); 
+0

私はここでEnumMapについて非常に具体的に話しています。 entrySetイテレータは次のようになります。 public Map.Entry next(){ if(!hasNext()) throw new NoSuchElementException(); lastReturnedEntry =新しいエントリ(インデックス++); return lastReturnedEntry; } – hawk

1

私は反射的にオブジェクトの作成に対する懸念のこのレベルの正当性を疑う

はい、良い方法があります。しかし、オブジェクトの作成を避けることが本当に重要な場合は、独自の列挙型の配列を維持し、それぞれに対してmap.contains(...)をテストすることができます。パフォーマンスの比較方法を調べるには、これをテストする必要があります。

+0

はいオブジェクトの作成が問題であるかどうかは問題ではありません。私はenum配列を保持することに頼ることなくこれを行う慣用方法を探しています。 – hawk

+0

なぜ列挙型配列を保持する必要がありますか? – marstran

+0

@marstran定数の 'int'順序を取る' EnumMap#contains(...) 'の形式がないためです。 –

関連する問題