2010-03-25 14 views
5

W moim kodowaniu java często kończę z kilkoma Map<String,Map<String,foo>> lub Map<String,List<String>>, a następnie mam problem z zapamiętaniem, który Ciąg jest kluczem. Komentarz do deklaracji z //Map<capabiltyId,Map<groupId,foo>> lub //Map<groupId,List<capabilityId>, ale to nie jest najlepsze rozwiązanie. Jeśli String nie byłby ostateczny, tworzyłbym nowe klasy CapabilityId extends String i GroupId extends String, ale nie mogę. Czy istnieje lepszy sposób na śledzenie, która rzecz jest kluczem i może kompilator ją wymusić?Lepsze bezpieczeństwo typów w kolekcjach Java

+0

Czy można użyć wyliczenia zamiast łańcucha? To może być przydatne, gdy masz dobrze zdefiniowane klucze. – Carl

Odpowiedz

7

Zamiast mieć CapabilityId przedłużyć String, CapabilityId może zawierać pole String o nazwie "id"; wtedy Twój Map może być zdefiniowany jako Map<CapabilityId, Map<GroupId, Foo>>, a możesz dostać się do indywidualnych pól identyfikacyjnych przez getId() na swoich klasach kluczy.

Nie jestem pewien, czy sam bym to zrobił, ale jeśli tak, to prawdopodobnie to zrobię.

Można ograniczyć bałagan poprzez klasę abstract GenericId z pola ID i getId() metody i mają CapabilityId i GroupId dziedziczyć po nim.

+0

To bardzo charakterystyczny komentarz Lincolna. –

+0

Przyznaję, że wybieram się do Jerry'ego Pournelle "Jeśli tego potrzebujesz, potrzebujesz go źle", ale na odwrót. –

+0

To jest dokładnie to, co zrobiłem wczoraj, aby wyśledzić wyciek pamięci; zamiast 150m obiektów String mogłem natychmiast zorientować się, która mapa nie była czyszczona, widząc, ile obiektów nnnnKey zostało utworzonych. – rhu

9

struny owijane w otoki-klas, jeśli chcesz:

class GroupId implements Comparable { 
    private String groupId; 

    public GroupId (String groupId) { 
     this.groupId = groupId; 
    } 
    ... 
} 

Map<GroupId, List<CapabilityId>> m = ... 
+0

Dlaczego warto stosować Porównywalne? –

3

Utwórz klasę ID które można podklasy, i który składa się z pola String i wdrożeń equals() i hashCode() które używają tego pola.

0

Dodawanie do innych odpowiedzi:

owinąć go.

To nie jest tylko rozwiązanie twojego problemu, ale ogólnie dobry pomysł, to jest uniknięcie prostych parametrów . Twój kod zyska czytelność, rozsądek i łatwość konserwacji. Możesz dodać do niego wszystkie miłe właściwości, np. zadeklaruj to @Immutable. Jak się dowiedziałeś, w ten sposób lepiej jest pamiętać i kontrolować. Jesteś właścicielem klasy i możesz robić z nią, co chcesz.

2

Umieściłbym wszystko w jednej klasie i użyłbym rozsądnych nazw pól/metod/argumentów.

public class GroupCapabilities { 
    private Map<String, Map<String, Group>> groupCapabilities; 

    public void addGroup(String capabilityId, Group group) { 
     Map<String, Group> groups = groupCapabilities.get(capabilityId); 
     if (groups = null) { 
      groups = new HashMap<String, Group>(); 
      groupCapabilities.put(capabilityId, group); 
     } 
     groups.put(group.getId(), group); 
    } 

    public Map<String, Group> getGroups(String capabilityId) { 
     return groupCapabilities.get(capabilityId); 
    } 

    public Group getGroup(String capabilityId, String groupId) { 
     Map<String, Group> groups = groupCapabilities.get(capabilityId); 
     return (groups != null) ? groups.get(groupId) : null; 
    } 

    // Etc.. 
} 

W ten sposób można zobaczyć przy nazwie metody/argumentu, czego oczekuje/zwraca.

1

Istnieje wiele sposobów, aby przejść na ten jeden (niektóre już wspomniano):

  • Jak @Roman, owinąć ogólny rodzaj przeznaczenia w bardziej konkretnego typu, co daje silniejszą pisać. Silne dobre pisanie, IMO.
  • Jako @nanda, użyj bardziej szczegółowego typu kolekcji. Biblioteka Java jest trochę słaba w tym obszarze. To zależy od tego, co czujesz na temat zależności.
  • Jako @BalusC przenieś wszystkie icky stuff na icky klasy. Naprawdę nie usuwa problemu, ale go zawiera (jak w Ghostbusters).
  • Map<String,Map<String,foo>> wygląda bardzo podobnie do klucza złożonego, tj. Klucza składającego się z dwóch części. Dlatego wprowadź niezmienną klasę złożonego klucza, czyli obiekt wartości reprezentujący obiekty wartości dwóch składników.