Jag vill lägga till värden i en HashMap
, som skulle användas med metoder i samma klass. Jag har två lösningar:
- Lägga till alla värden med
static
- När den första metoden anropas, lägg till värdena
Lösning nr 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", "..-."); // ... }
Lösning # 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", "..-."); // ... }
Vilken är den mest effektiva? Vilken är den bästa praxis?
Kommentarer
- Varför lägger du det till en HashMap i första hand? Varför inte en matris med 26 strängar?
- Hur löser en matris med 26 strängar detta problem? I synnerhet hur man gör kartläggningen? Du har den implicita konverteringen från A – > 0, B – > 0, …, i åtanke?
- @Ali en sista grupp hanterar oföränderlighet och initalisering. A- > 0, B- > 1 gör det ganska snyggt och undviker många andra frågor av andra bibliotek som behövs, extra statiska block eller byggare. Det ' är tydligt och rimligt.
- @MichaelT Kanske för detta speciella exempel, med tanke på att användaren vill ha mappning för morse-koden, en rad strängar av storlek 26 är bra, men det är ingen allmän lösning. Mitt svar gick mot en allmän lösning, inte den här specifika. I många fall är domänen så stor att vi inte kan använda en direkt mappning till heltal och vi måste använda en hashmap.
- @MichaelT btw, en array är bara storleksmässig oföränderlig, men du kan ändra ett av dess element. a [0] = " ny val ".
Svar
Din lösning 1 kan vara problematisk, eftersom hashmap är statisk och initialiseras bara en gång och delas av alla instanser i din klass. Är detta ditt avsedda beteende eller vill du att varje instans har sin egen karta? Om du bara en karta, föreslår jag att du skickar uppsättningen till konstruktören istället för att använda en statisk, till exempel:
public class Data { private final Map<Character, String> codes; public Data(Map<Character, String> codes) { this.codes = codes} }
Din lösning 2 lägger till omkostnaderna för lat initiering av uppsättningen, varje gång du behöver den, och lägger till den fula kryssrutan methodIsCalled
till logiken i ditt program. Jag tycker att initiering av kartan i konstruktören är ett bättre alternativ.
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", "..-."); } }
Den andra frågan du behöver svara är att om du ändrar värdena för denna hashmap senare eller inte. Om du inte ändrar det bör du leta efter oföränderliga hashMaps. Ett alternativ är att använda Collections.unmodifiableMap (karta).
Du kan också använda Google Guava-bibliotek så att du kan initiera en karta i en rad och få en oföränderlig karta:
ImmutableMap.<Character, String>builder() .put("A", ".-") .put("B", "-...") .put("C", "-.-.") .put("D", "-..") .put("E", ".") .put("F", "..-.") .build();
Svar
Ingenting kan slå Guavas ImmutableMap med sin optimerade minneskonsumtion, men här är ett par rena lösningar:
/* 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", "..-."); // ... } }); }
Svar
Om du inte insisterar på lat initialisering (och för en liten, icke-växande karta med 26 objekt bör du inte t), varför inte optimera för läsbarheten istället? Jag skulle alltid använda något som
private static Map<Character, String> codes = newMap( "A", ".-", "B", "-...", "C", "-.-.", ... );
(med en lämpligt definierad hjälpfunktion newMap
).
Kommentarer
- Kan du till och med skriva newMap med parameterpaket?
- @ VF1 Du kan, om du definierar det som en generisk funktion med varargs .
Svar
I dessa fall antar jag att frågan inte handlar om effektiv metod – utan snarare när gör du faktiskt behöver den kartan initialiseras och redo ..
vid statisk initialisering – när tidsklassen laddas
kan din lazy loading-metod vara nödvändig om du behöver ställa in ”enormt ”kartlägg och säg ofta att dessa värden kommer från en dyr källa (dvs. över nätverket), även då kanske du inte behöver en extern flagga.
Collection.isEmpty () skulle berätta om det redan har initierats eller inte (förutsatt, naturligtvis skulle minst ett värde vara där för att initialiseras)