Javaのプリミティブのマップ
1. 概要
このチュートリアルでは、
ご存知のように、コアJava Maps は、プリミティブキーまたは値の保存を許可していません。 そのため、プリミティブマップの実装を提供する外部のサードパーティライブラリをいくつか紹介します。
2. Eclipseコレクション
Eclipseコレクションは、Java用の高性能コレクションフレームワークです。 改善された実装と、いくつかのプリミティブコレクションを含むいくつかの追加のデータ構造を提供します。
2.1. 可変および不変マップ
キーと値の両方がプリミティブintである空のマップを作成しましょう。 そのために、IntIntMapsファクトリクラスを使用します。
MutableIntIntMap mutableIntIntMap = IntIntMaps.mutable.empty();
IntIntMapsファクトリクラスは、プリミティブマップを作成するための最も便利な方法です。 これにより、目的のタイプのマップの可変インスタンスと不変インスタンスの両方を作成できます。 この例では、IntIntMapの可変インスタンスを作成しました。 同様に、IntIntMaps.mutable静的ファクトリ呼び出しをIntIntMaps.immutableに置き換えるだけで、不変のインスタンスを作成できます。
ImmutableIntIntMap immutableIntIntMap = IntIntMaps.immutable.empty();
それでは、キーと値のペアを可変マップに追加しましょう。
mutableIntIntMap.addToValue(1, 1);
同様に、参照型とプリミティブ型のキーと値のペアを使用して混合マップを作成できます。 Stringキーとdouble値を使用してマップを作成しましょう。
MutableObjectDoubleMap dObject = ObjectDoubleMaps.mutable.empty();
ここでは、 ObjectDoubleMaps ファクトリクラスを使用して、MutableObjectDoubleMapの可変インスタンスを作成しました。
次に、いくつかのエントリを追加しましょう。
dObject.addToValue("price", 150.5);
dObject.addToValue("quality", 4.4);
dObject.addToValue("stability", 0.8);
2.2. プリミティブAPIツリー
Eclipseコレクションには、 PrimitiveIterableと呼ばれる基本インターフェースがあります。これは、ライブラリーの各プリミティブコンテナーの基本インターフェースです。 すべてPrimitiveTypeIterableという名前が付けられます。ここで、 PrimitiveTypeはInt、Long 、 Short 、 Byte 、になります。 Char 、 Float 、 Double 、またはBoolean。
これらのすべてのベースインターフェイスには、 XY Map 実装のツリーがあり、マップが可変か不変かによって分割されます。 例として、 IntIntMap の場合、MutableIntIntMapとImmutableIntIntMapがあります。
最後に、上で見たように、キーのタイプとプリミティブ値とオブジェクト値の両方の値のすべての種類の組み合わせをカバーするインターフェイスがあります。 だから、例えば、私たちは持つことができます IntObjectMap
3. HPPC
HPPC は、高性能とメモリ効率を目的としたライブラリです。 これは、ライブラリの抽象化が他のライブラリよりも少ないことを意味します。 ただし、これには、内部を有用な低レベルの操作にさらすという利点があります。 マップとセットの両方を提供します。
3.1. 簡単な例
intキーとlong値を持つマップを作成することから始めましょう。 これを使用することはかなりなじみがあります:
IntLongHashMap intLongHashMap = new IntLongHashMap();
intLongHashMap.put(25, 1L);
intLongHashMap.put(150, Long.MAX_VALUE);
intLongHashMap.put(1, 0L);
intLongHashMap.get(150);
HPPCは、キーと値のすべての組み合わせのマップを提供します。
- プリミティブキーとプリミティブ値
- プリミティブキーとオブジェクトタイプの値
- オブジェクトタイプのキーとプリミティブ値
- オブジェクトタイプのキーと値の両方
オブジェクトタイプマップはジェネリックをサポートします:
IntObjectOpenHashMap<BigDecimal>
ObjectIntOpenHashMap<LocalDate>
最初のマップには、プリミティブintキーとBigDecimal値があります。 2番目のマップには、キーに LocalDate があり、値にintがあります。
3.2. ハッシュマップとスキャッターマップ
キーのハッシュ関数と分散関数の従来の実装方法が原因で、キーをハッシュするときに衝突が発生する可能性があります。 キーの配布方法によっては、これが巨大なマップのパフォーマンスの問題につながる可能性があります。 デフォルトでは、HPPCはこの問題を回避するソリューションを実装しています。
ただし、より単純な分布関数を備えたマップの場所はまだあります。 これは、マップがルックアップテーブルとして、またはカウントに使用される場合、またはロードされた後に多くの書き込み操作を必要としない場合に便利です。 HHPCは、スキャッターマップを提供して、パフォーマンスをさらに向上させます。
すべてのスキャッターマップクラスは、マップと同じ命名規則を維持しますが、代わりにScatterという単語を使用します。
- IntScatterSet
- IntIntScatterMap
- IntObjectScatterMap
4. Fastutil
Fastutilは、プリミティブ型マップを含む型固有のコレクションを提供する高速でコンパクトなフレームワークです。
4.1. 簡単な例
EclipseコレクションおよびHPPCに似ています。 Fastutilは、プリミティブからプリミティブ、およびプリミティブからオブジェクトの型付き関連付けマップも提供します。
intからbooleanへのマップを作成しましょう。
Int2BooleanMap int2BooleanMap = new Int2BooleanOpenHashMap();
そして今、いくつかのエントリを追加しましょう:
int2BooleanMap.put(1, true);
int2BooleanMap.put(7, false);
int2BooleanMap.put(4, true);
次に、そこから値を取得できます。
boolean value = int2BooleanMap.get(1);
4.2. インプレース反復
Iterable インターフェースを実装する標準のJVMコレクションは、通常、各反復ステップで新しい一時イテレーターオブジェクトを作成します。 膨大なコレクションがあると、ガベージコレクションの問題が発生する可能性があります。
Fastutilは、これを大幅に軽減する代替手段を提供します。
Int2FloatMap map = new Int2FloatMap();
//Add keys here
for(Int2FloatMap.Entry e : Fastutil.fastIterable(map)) {
//e will be reused on each iteration, so it will be only one object
}
Fastutilは、fastForeachメソッドも提供します。 これにより、 Consumer 機能インターフェイスが使用され、ループごとにラムダ式が実行されます。
Int2FloatMap map = new Int2FloatMap();
//Add keys here
Int2FloatMaps.fastForEach(map , e -> {
// e is also reused across iterations
});
これは、標準のJava foreach構造と非常によく似ています。
Int2FloatMap map = new Int2FloatMap();
//Add keys here
map.forEach((key,value) -> {
// use each key/value entry
});
5. 結論
この記事では、Eclipseコレクション、HPPC、およびFastutilを使用してJavaでプリミティブマップを作成する方法を学習しました。
いつものように、この記事のサンプルコードは、GitHubでから入手できます。