HashMap
に値を追加したいのですが。これは同じクラス。 2つの解決策があります:
-
static
- 最初のメソッドが呼び出されたら、値を追加します
ですべての値を追加する
ソリューション#1:
private static Map<Character, String> codes = new HashMap<>(); static { codes.put("A", ".-"); codes.put("B", "-..."); codes.put("C", "-.-."); codes.put("D", "-.."); codes.put("E", "."); codes.put("F", "..-."); // ... }
ソリューション#2:
boolean methodIsCalled = false; public static char decode(String s) { if(!methodIsCalled) { addValues(); methodIsCalled = true; } // ... } private static void addValues() { codes.put("A", ".-"); codes.put("B", "-..."); codes.put("C", "-.-."); codes.put("D", "-.."); codes.put("E", "."); codes.put("F", "..-."); // ... }
どれが最も効率的ですか?ベストプラクティスはどれですか?
コメント
- そもそもなぜそれをHashMapに入れるのですか? 26文字列の配列ではないのはなぜですか?
- 26文字列の配列はこの問題をどのように解決しますか?特に、どのようにマッピングを行いますか? A- > 0、B- > 0、…からの暗黙的な変換を念頭に置いていますか?
- @Ali最終配列は、不変性と初期化を処理します。 A- > 0、B- > 1は、必要な他のライブラリ、追加の静的ブロック、またはビルダー。 'は明確で合理的です。
- @MichaelTユーザーがモールス信号、文字列の配列のマッピングを希望している場合、この特定の例ではおそらくサイズ26の場合は問題ありませんが、一般的な解決策ではありません。私の答えは、この特定の解決策ではなく、一般的な解決策に向けられました。多くの場合、ドメインが非常に大きいため、整数への直接マッピングを使用できず、ハッシュマップを使用する必要があります。
- @MichaelTところで、配列はサイズ的に不変ですが、変更できます。その要素の1つ。 a [0] = " new val "。
回答
ハッシュマップは静的であり、一度だけ初期化され、クラスのすべてのインスタンスで共有されるため、ソリューション1に問題がある可能性があります。これは意図した動作ですか、それとも各インスタンスに独自のマップを持たせたいですか?マップが1つしかない場合は、静的なマップを使用する代わりに、セットをコンストラクターに渡すことをお勧めします。例:
public class Data { private final Map<Character, String> codes; public Data(Map<Character, String> codes) { this.codes = codes} }
ソリューション2は次のように追加します。セットの遅延初期化のオーバーヘッドは、必要になるたびに、醜いチェックmethodIsCalled
をプログラムのロジックに追加します。コンストラクターでマップを初期化する方が良いオプションだと思います。
public class Data { private final Map<Character, String> codes; public Data() { this.codes = new HashMap<>(); codes.put("A", ".-"); codes.put("B", "-..."); codes.put("C", "-.-."); codes.put("D", "-.."); codes.put("E", "."); codes.put("F", "..-."); } }
このハッシュマップの値を後で変更した場合、答える必要があるもう1つの質問です。か否か。変更しない場合は、不変のハッシュマップを探す方がよいでしょう。1つのオプションは、Collections.unmodizableMap(map)を使用することです。
Google Guavaライブラリを使用して、マップを初期化することもできます。 1行で不変のマップを取得します:
ImmutableMap.<Character, String>builder() .put("A", ".-") .put("B", "-...") .put("C", "-.-.") .put("D", "-..") .put("E", ".") .put("F", "..-.") .build();
回答
他に勝るものはありません最適化されたメモリ消費を備えたGuavaのImmutableMapですが、純粋なソリューションのペアは次のとおりです。
/* Name of the class has to be "Main" only if the class is public. */ class Ideone { private static final Map<Character, String> codes1; static { Map<Character, String> temp= new HashMap<Character, String>(); temp.put("A", ".-"); temp.put("B", "-..."); temp.put("C", "-.-."); temp.put("D", "-.."); temp.put("E", "."); temp.put("F", "..-."); // ... codes1 = Collections.unmodifiableMap(temp); } private static final Map<Character, String> codes2 = Collections.unmodifiableMap(new HashMap<Character, String>() { { put("A", ".-"); put("B", "-..."); put("C", "-.-."); put("D", "-.."); put("E", "."); put("F", "..-."); // ... } }); }
回答
怠惰な初期化を主張しない場合(そして、26項目の小さくて成長しないマップの場合は、そうすべきではありません)、代わりに読みやすさを最適化してみませんか?私はいつも
private static Map<Character, String> codes = newMap( "A", ".-", "B", "-...", "C", "-.-.", ... );
(適切に定義されたヘルパー関数newMap
)のようなものを使用します。
コメント
- パラメータパックを使用してnewMapを作成することもできますか?
- @ VF1 varargsを使用して汎用関数として定義すると、作成できます。 。
回答
このような場合、質問は効率的な方法ではなく、いつ行うのかということだと思います。実際には、マップを初期化して準備ができている必要があります。
静的初期化の場合-クラスが読み込まれるまでに
「huge」を設定する必要がある場合は、遅延読み込みアプローチが必要になることがあります。 “マップし、これらの値は高価なソース(つまり、ネットワーク全体)からのものであることが多いと言いますが、それでも外部フラグは必要ない場合があります。
Collection.isEmpty()は、それがすでに初期化されているかどうかを示します。またはそうでない(もちろん、少なくとも1つの値が初期化される場合)