3

私はよくマップを使用して、同じクラス/グループに関連するオブジェクトのセット/リストや、インクリメントしたいAtomicIntegerなどの値をループに格納します。したがって、私はしばしば次の種類のコードを記述します(マップにnullを格納しないと仮定します)。

/* Example #1 -- aggregation */
Map<K, Set<O>> map = new HashMap<K, Set<O>>();
for (O o : oList) {
    K k = o.getK();
    Set<O> oSet = map.get(k);
    if (oSet == null) {
        oSet = new HashSet<O>(o);
        map.put(k, oSet);
    } else {
        oSet.add(o);
    }
}

/* Example #2 -- counting */
Map<K, AtomicInteger> map = new HashMap<K, AtomicInteger>();
for (O o : oList) {
    K k = o.getK();
    AtomicInteger i = map.get(k);
    if (i == null) {
        i = new AtomicInteger(1);
        map.put(k, i);
    } else {
        i.increment();
    }
}

DefaultedMapファクトリ/モデルオブジェクトが欠落しているときにその場で値を作成できるApacheCommonコレクションを知っています。しかし、2/3行のコードを書くという(かなり小さな)煩わしさを避けるために、(別の)外部ライブラリに依存しています。

より簡単な解決策はありますか(特にたとえば#2)?その場合、他の開発者は何を使用/推奨しますか?この種の「デフォルトマップ」を提供している他のライブラリはありますか?あなたはあなた自身の装飾された地図を書きますか?

4

3 に答える 3

8

Java 8では、メソッドがインターフェースcomputeIfAbsent()に追加されました。Map

default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

指定されたキーがまだ値に関連付けられていない(またはnullにマップされている)場合、指定されたマッピング関数を使用してその値を計算し、nullでない限りこのマップに入力しようとします。

ドキュメントによると、最も一般的な使用法は、初期マップ値として新しいオブジェクトを作成するか、複数値マップを実装することです。例えば:

map.computeIfAbsent(key, k -> new HashSet<V>()).add(v);

したがって、例を次のように書き直すことができます。

/* Example #1 -- aggregation */
Map<K, Set<O>> map = new HashMap<>();
oList.forEach(o -> map.computeIfAbsent(o.getK(), k -> new HashSet<>()).add(o));

/* Example #2 -- counting */
Map<K, AtomicInteger> map = new HashMap<>();
oList.forEach(o -> map.computeIfAbsent(o.getK(), k -> new AtomicInteger(0)).incrementAndGet());

もう1つのオプションは、StreamAPIを次のものと一緒に使用することCollectors.groupingByです。

/* Example #1 -- aggregation */
Map<K, Set<O>> map = oList.stream()
                          .collect(Collectors.groupingBy(O::getK, Collectors.toSet()));

/* Example #2 -- counting using a Long instead of an AtomicInteger */
Map<K, Long> map = oList.stream()
                        .map(O::getK)
                        .collect(Collectors.groupingBy(k -> k, Collectors.counting()));
于 2015-07-07T18:06:14.997 に答える
3

Googleのguava-librariesもそのようなマップの実装を提供します。しかし、私はそのような小さな利益のためだけにライブラリを使用することはありません。すでにそのようなライブラリを使用している場合は、マップの使用を検討できます。しかし、一般的に、これは私の意見にすぎません。些細なことにライブラリを使用するのは好きではありません。

あなたの質問の例は私には問題ないようです。私もこのイディオムを使っています。

于 2013-03-21T15:23:33.680 に答える
1

私には、JavaWSの一部としてのMultivaluedMapのように見えます。

そして、SpringFrameworkによって実装されたものと同じです

したがって、あなたの質問に答えるには、これに対するデフォルトの実装はなく、独自の実装をロールするか、実装の1つをより適切に使用する必要があります。

于 2013-03-21T15:26:23.677 に答える