質問

私は、マップインスタンスをハンドバックする異なるカスタム(ソースコードが利用できない)フレームワークによって行われているピースワークの部分を持っています。残念ながら、これらのフレームワークは、collections.unmodifiablemapに包まれた戻ってきたマップインスタンスで一貫していません。コードでより高い程度の不変性(マルチスレッドの使用が容易になる)を確保するために、これらのフレームワークによって返されるものについて、collections.unmodifiablemapと均一に呼ばれました。

Map<String, Record> immutableMap = framework.getRecordsByName();
//does this created a nested set of unmodifiableMap wrapper instances?
this.immutableField = Collections.unmodifiableMap(immutableMap);
.
.
.
Map<String, Record> maybeImmutableMap = framework.getRecordsByName();
//is there some means to get instanceof to work?
if (!(maybeImmutableMap instanceof Collections.UnmodifiableMap))
{
    this.immutableField = Collections.unmodifiableMap(maybeImmutableMap);
}

私は自分のデザインのこの部分についてパフォーマンスの問題があるかもしれないことに気付きました。そして、場合によっては、私はcollections.unmodifiablemapを呼び出していましたが、同じ呼び出しによってフレームワークに既にラップされていたインスタンスを渡しました。そして、私の再ラッピングがインスタンス全体で追加のメソッド呼び出しを引き起こす可能性が高いこと。

「Instanceof collections.unmodifiablemap」を使用することは機能しないようです。そして、私が現在参照しているマップインスタンスをラップする必要があるかどうかを検出する方法を見つけることができません(この状況ではオプションではない反射を使用することを除外します - あまりにも遅すぎます)。

質問:

    a)collections.unmodifiablemap()メソッドは、unmodifiablemapのインスタンスに渡されたかどうかを確認します。そうであれば、同じ参照を返すだけです(メソッドを呼び出す前に確認する必要性を回避します)。
    b)修正の例外の受信を積極的に回避するために、マップインスタンス(反射を使用する以外)をクエリする方法はありますか?
    c)Aへの答えがNOの場合、JVM/ホットスポットには、複数のメソッドがコアインスタンスに到達するためにホップを介して呼び出しのオーバーヘッドを排除する効率がありますか?
役に立ちましたか?

解決 4

すべてのフィードバックをレビューした後、私は私が何をしても、解決策は何らかの形のクラッジ(軽度の臭いがする)になるという結論に達しました。これは、変更できないインスタンスを生成するコレクションAPIの一部が、巣のないインスタンスを避けるために提供されなかったため、クライアントがネストを適切に回避するための「公開」方法を提供しなかったという事実によると思います。

また、複数のクラスローダーに関する考慮事項とRMIを介したシリアル化により、私が本当に気に入った1つのソリューション(Jorn Horstmannによるクラス参照比較)に問題があります。しかし、彼のアプローチを取り、クラス名のアプローチ(ユージン・クレシュフが推奨)の変更と組み合わせると、マルチスレッドで役立つソリューションを手に入れるのと同じくらい近くになると思います。分散処理環境。そして、それはこのようになります:

public class MyCollections {
    private static final String UNMODIFIABLE_MAP_CLASS_NAME =
        Collections.unmodifiableMap(new HashMap()).getClass().getName();

    public static <K, V> Map<K, V> unmodifiableMap(Map<K, V> map) {
        return map.getClass().getName().equals(UNMODIFIABLE_MAP_CLASS_NAME)
                 ? map
                 : Collections.unmodifiableMap(map);
    }
}

これには、参照比較のすべての利点がまだあります 仮定します すべてが同じクラスローダーコンテキスト内で起こっています ClassNameの文字列は適切にインターンされています。そして、それはカプセル化を丁寧に維持しながらそれを行います(クラス名を直接参照するコードを避けます)。ただし、2つの仮定が当てはまらない場合、評価は、クラス名がライブラリの異なるバージョン間で変更されないと仮定して機能する標準の文字列比較に戻ります(確率がかなり低いようです)。

このアプローチで私が忘れている、または欠けているものはありますか?

そして、皆さん、あなたのフィードバックをありがとう。ほんとうにありがとう。

他のヒント

私の知る限りでは:

  • a)いいえ
  • b)いいえ
  • c)いいえ

グアバ's Immutable* コレクションにはこの問題はありません。もしも ImmutableList.copyOf(list) と呼ばれます list それ自体がです ImmutableList, 、議論自体が返されます。さらに、あなたはそれらを次のように参照することができます(そして、 instanceof のために Immutable* インターフェイスではなくタイプし、不変のインスタンスがあるかどうかを簡単に知ることができます。したがって、1つのオプションは、フレームワークの結果をこれらの不変のコレクションにコピーし、独自のコード全体でそれらを使用することです。 (彼らはまた、本当に不変であるという利点を持っています...変更できないラッパーは、何かがそれを参照している場合、彼らが包む元の可変インスタンスを自分自身で変異させることを可能にします。)

とはいえ、メソッドコールを1つまたは2つの変更できないラッパーレイヤーに通過させる可能性のあるオーバーヘッドについてあまり心配しません。他の人が指摘したように、このためにパフォーマンスの問題に気付くことはほとんどありません。

1つの変更できないマップを別のマップに包むとき、パフォーマンスを心配する必要はありません。見て UnmodifiableMap クラス:

private static class UnmodifiableMap<K,V> implements Map<K,V>, Serializable {
    ...
UnmodifiableMap(Map<? extends K, ? extends V> m) {
        if (m==null)
            throw new NullPointerException();
        this.m = m;
    }

public int size()                {return m.size();}
    ...
public V put(K key, V value) {
    throw new UnsupportedOperationException();
    }
public V remove(Object key) {
    throw new UnsupportedOperationException();
    }

public Set<K> keySet() {
    if (keySet==null)
    keySet = unmodifiableSet(m.keySet());
    return keySet;
}

public Set<Map.Entry<K,V>> entrySet() {
    if (entrySet==null)
    entrySet = new UnmodifiableEntrySet<K,V>(m.entrySet());
    return entrySet;
}
    ...

このクラスは、実際の地図の周りの薄いラッパーにすぎないことがわかります。すべての方法のような getSize, isEmpty MAPの状態に影響しない他の方法は、ラップされたMAPインスタンスに委任されます。 MAPの状態に影響する他の方法(put, remove)投げるだけです UnsupportedOperationException したがって、パフォーマンスの過負荷はほぼゼロです。

(c)についての私の考えは、ホットスポットコンパイラが別のメソッド呼び出しの結果を返すだけの小さなメソッドを導入するのにかなり上手くなければならないということです。しかし、私はそれがいくつかのレベルの間接を通して見ることができるとは思わない。たとえば、いくつかの非モジーマップに包まれたハッシュマップ。また、あなたのライブラリが変更できないマップを返すことがあることを知っていれば、それは時期尚早の最適化になるとは思いません。 Collections.unmodifiablemapのように、コレクションのために独自のラッパーを作成してみませんか(テストされていないので、コレクションのImpleがプライベートであるため、単純なインスタンスが機能しないことに気付きました):

public class MyCollections {
    private static final Class UNMODIFIABLE_MAP_CLASS = Collections.unmodifiableMap(new HashMap()).getClass();

    public static <K, V> Map<K, V> unmodifiableMap(Map<K, V> map) {
        return map.getClass() == UNMODIFIABLE_MAP_CLASS ? map : Collections.unmodifiableMap(map);
    }
}

a)いいえ

b)いいえ

c)おそらく、しかし、私はそれがJVMのインプレンスに依存することを期待するでしょう。

問題のデコレーターは非常に軽量です。別のメソッドコールを作成する追加のメソッドコールが環境にいくつかのパフォーマンスの問題を引き起こすという具体的な理由はありますか?これは標準アプリケーションでは問題ではないはずなので、本当に特別なアプリケーション/環境(CPU集中、リアルタイム、モバイルデバイス...)がない限り、問題はありません。

一般的に、最初のルールは、実際に必要でない限り、最適化しないことです。基本的に、アプリケーションからいくつかのパフォーマンスデータを収集して、ラップコレクションがパフォーマンスヒットを引き起こすかどうかを確認する必要があります。

ただし、コレクションが変更できないかどうかを本当に確認する場合は、「Unmodifiablemap」.equals(class.getSimplename())を確認できます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top