Chcę dodać wartości do HashMap
, które będą używane przez metody w sama klasa. Mam dwa rozwiązania:
- Dodanie wszystkich wartości za pomocą
static
- Po wywołaniu pierwszej metody dodaj wartości
Rozwiązanie 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", "..-."); // ... }
Rozwiązanie nr 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", "..-."); // ... }
Który z nich jest najbardziej wydajny? Która z nich jest najlepsza?
Komentarze
- Dlaczego umieszczasz to w HashMap w pierwszej kolejności? Dlaczego nie tablica 26 ciągów?
- W jaki sposób tablica 26 ciągów rozwiązuje ten problem? W szczególności, jak wykonać mapowanie? Masz na myśli niejawną konwersję z A – > 0, B – > 0, …?
- @Ali ostateczna tablica obsługuje niezmienność i inicjalizację. A- > 0, B- > 1 robi to całkiem przyjemnie, unikając wielu innych problemów z innymi potrzebnymi bibliotekami, dodatkowych bloków statycznych lub budowniczych. To ' jest jasne i rozsądne.
- @MichaelT Może w tym konkretnym przykładzie, biorąc pod uwagę, że użytkownik chce mieć odwzorowanie kodu Morsea, tablicę ciągów rozmiaru 26 jest w porządku, jednak nie jest to rozwiązanie ogólne. Moja odpowiedź była w kierunku rozwiązania ogólnego, a nie tego konkretnego. W wielu przypadkach domena jest tak duża, że nie możemy użyć bezpośredniego mapowania na liczby całkowite i musimy użyć hashmap.
- @MichaelT btw, tablica jest niezmienna tylko pod względem rozmiaru, ale można ją zmienić jeden z jego elementów. a [0] = " new val ".
Odpowiedź
Twoje rozwiązanie 1 może być problematyczne, ponieważ hashmap jest statyczny i zostanie zainicjowany tylko raz i jest współdzielony przez wszystkie instancje Twojej klasy. Czy jest to Twoje zamierzone zachowanie, czy też chcesz, aby każda instancja miała własną mapę? Jeśli masz tylko jedną mapę, sugerowałbym przekazanie zestawu do konstruktora zamiast używania statycznego, na przykład:
public class Data { private final Map<Character, String> codes; public Data(Map<Character, String> codes) { this.codes = codes} }
Twoje rozwiązanie 2 dodaje narzut leniwej inicjalizacji zbioru za każdym razem, gdy tego potrzebujesz, i dodaje brzydkie sprawdzenie methodIsCalled
do logiki twojego programu. Myślę, że zainicjowanie mapy w konstruktorze jest lepszą opcją.
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", "..-."); } }
Innym pytaniem, na które musisz odpowiedzieć, jest to, że jeśli później zmienisz wartości tego skrótu albo nie. Jeśli tego nie zmienisz, lepiej poszukaj niezmiennych map skrótów. Jedną z opcji jest użycie Collections.unmodifiableMap (mapa).
Możesz także użyć bibliotek Google Guava, aby umożliwić zainicjowanie mapy w jedna linia i uzyskaj niezmienną mapę:
ImmutableMap.<Character, String>builder() .put("A", ".-") .put("B", "-...") .put("C", "-.-.") .put("D", "-..") .put("E", ".") .put("F", "..-.") .build();
Odpowiedź
Nic nie może przebić ImmutableMap guawy ze zoptymalizowanym zużyciem pamięci, ale oto kilka czystych rozwiązań:
/* 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", "..-."); // ... } }); }
Odpowiedź
Jeśli nie nalegasz na leniwą inicjalizację (a dla małej, nierozrastającej się mapy 26 elementów nie powinieneś tego robić), to dlaczego nie zoptymalizować zamiast tego pod kątem czytelności? Zawsze używałbym czegoś takiego jak
private static Map<Character, String> codes = newMap( "A", ".-", "B", "-...", "C", "-.-.", ... );
(z odpowiednio zdefiniowaną funkcją pomocniczą newMap
).
Komentarze
- Czy możesz nawet napisać newMap z pakietami parametrów?
- @ VF1 Możesz, jeśli zdefiniujesz ją jako funkcję ogólną z varargs .
Odpowiedź
Przypuszczam, że w takich przypadkach pytanie nie dotyczy skutecznej metody – ale raczej kiedy faktycznie potrzebujesz zainicjalizowanej i gotowej mapy ..
w przypadku statycznej inicjalizacji – do czasu załadowania klasy
Twoje podejście z opóźnionym ładowaniem może być konieczne, jeśli chcesz ustawić „ogromne „map i powiedz, że często te wartości pochodzą z drogiego źródła (np. z sieci), nawet wtedy możesz nie potrzebować flagi zewnętrznej.
Collection.isEmpty () powie ci, czy została już zainicjowana lub nie (pod warunkiem, że byłaby tam co najmniej jedna wartość do zainicjowania)