可変数値オブジェクト

ご存知のように、Javaには、数値(バイト、ショート、整数、ロング、フロート、ダブル)のプリミティブ型と、その上のオブジェクトラッパー(バイト、ショート、整数、ロング、フロート、ダブル)があります。 さまざまな記事で、使用するものについて正反対の推奨事項を見つけることができます。 一方、オブジェクトラッパーは普遍的です。便利でカプセル化された、一般的に美しい標準コレクションで使用できます。 ただし、ボクシングはパフォーマンスを低下させ、多くのメモリを消費します。 プリミティブ型は高速でコンパクトですが、書き込みから保護できない配列にのみ配置でき、抽象化はゼロです。 Mapのようなものを何かにマップする必要がある場合は、パフォーマンスとメモリの損失を我慢するか、非標準インターフェイスを実装するサードパーティライブラリを使用する必要があります。 ただし、場合によっては可変数が役立ちます。



どこかから来るさまざまな行の数を数える必要があると想像してください。 多くの場合、次のようなコードが作成されます。



public Map<String, Integer> countStrings() { Map<String, Integer> counts = new HashMap<String, Integer>(); while(true) { String next = getNextString(); if(next == null) break; Integer val = counts.get(next); if(val == null) counts.put(next, 1); else counts.put(next, val+1); } return counts; }
      
      





それほど多くの種類の行がなく、十分な繰り返しがある場合、ボクシングは数百万の一時的な整数オブジェクトを作成し、ガベージコレクターはそれをクリーンアップします。 想像するのは怖いです。 いいえ、これは壊滅的なほど遅くはありませんが、それでも手順を2〜3回高速化することは難しくありません。 このために、MutableIntegerを使用します。



このようなクラスはいくつかのライブラリー(たとえばorg.apache.commons.lang )に存在しますが、自分で作成することは難しくありません。 単純な実装は次のようになります。



 public class MutableInteger { private int value; public MutableInteger(int value) { this.value = value; } public int intValue() { return value; } public void set(int value) { this.value = value; } public void increment() { value++; } public String toString() { return String.valueOf(value); } }
      
      





次に、算術演算の簡単なメソッドを追加できます。 Numberを継承し、Comparableインターフェイスを実装し、equalsとhashCodeを忘れないようにすることも便利です(hashCodeでは、単に値を返すことができます)。 しかし、現在のタスクについては、書かれているもので十分です。 countStrings()は次のように書き換えられるようになりました。



 public Map<String, MutableInteger> countStrings() { Map<String, MutableInteger> counts = new HashMap<String, MutableInteger>(); while(true) { String next = getNextString(); if(next == null) break; MutableInteger val = counts.get(next); if(val == null) counts.put(next, new MutableInteger(1)); else val.increment(); } return counts; }
      
      





もちろん、Map <String、MutableInteger>を返すことで実装の詳細を公開するのは良くありませんが、java.lang.Numberを継承する場合、Map <String、Number>を返すことができます。 さて、または最後の手段として、数えた後、すべてを新しいマップにコピーします。 同様に、数量だけでなく、オブジェクトのセットに関する他の統計も収集できます。



また、java.util.concurrent.atomic.AtomicIntegerも本質的にMutableIntegerであることに注意してください。ただし、原子性のオーバーヘッドは最初の例のオブジェクトとガベージコレクションの作成コストを超えることもあるため、別個のクラスMutableIntegerが必要です。



All Articles