2015-12-01 17 views
6

Potrzebuję utworzyć mapę, która będzie buforować wyniki usługi wyszukiwania stron trzecich. Żądanie składa się z dwóch obiektów, na przykład: time i month. Mapa musi być mapowana między (time, month) a wynikiem.Java Map między parami i wartościami

Moim początkowym pomysłem jest uczynienie obiektu, który będzie skutecznie owijał obiekt krotki, co oznacza, że ​​pamięć podręczna jest mapą między tym obiektem a wynikiem.

Czy istnieje lepszy sposób robienia tego bez potrzeby zawijania żądania do obiektu krotki za każdym razem, gdy potrzebujemy korzystać z pamięci podręcznej?

Wielkie dzięki.

+1

Czas i miesiąc .. mmhh, a co z łączeniem go z datą i tworzeniem klucza mapy? –

+1

"Czy jest lepszy sposób na robienie tego" Co sądzisz o tym źle? –

+1

Czy możesz podać przykład zastosowania (ń) klasy, którą chcesz zrobić, oraz wyjątków? (Właściwie to nie jestem pewien, aby zrozumieć, co chciałbyś zrobić.) – RyDroid

Odpowiedz

5

Mój początkowy pomysł jest, aby przedmiot owinąć time i month się skutecznie obiektu krotki

To dobry pomysł. Przestawianie hashCode() i equals(Object) Twojego krotki, aby pracować z HashMap<TimeMonthTuple> lub compareTo(TimeMonthTuple) aby pracować z TreeMap<TimeMonthTuple>

Czy istnieje lepszy sposób to zrobić?

To jest najprostszy sposób, chyba że masz klasę, która może zastąpić TimeMonthTuple czymś, co ma sens. Na przykład czas i datę można połączyć w obiekt Date.

W niektórych przypadkach można utworzyć klucz na podstawie prymitywnego opakowania. Na przykład, jeśli time jest wyrażony jako liczba minut od północy i month jest liczbą z przedziału od 1 do 12 włącznie, można zawijać zarówno wartości do Integer i użyć go jako klucza:

Integer makeTimeMonthKey(int time, int month) { 
    return (time * 12) + (month - 1); 
} 
0

Powinieneś rzucić okiem na Guava Tables, jeśli chcesz uniknąć tworzenia obiektu opakowania.

0

Ty może stworzyć mapę map:

Map<MonthType, Map<TimeType, Value>> map; 

więc chcesz zadzwonić:

Value value = map.get(month).get(time); 

aby pobrać wartość (pod warunkiem, że wcześniej dodał VALU e dla month).

Nie jest szczególnie przyjemnie używać bezpośrednio, ponieważ potrzebne są liczne kontrole w liczbie: containsKey//null. Można owinąć go w klasie Wygoda:

class MapOfMaps { 
    final Map<MonthType, Map<TimeType, Value>> map = new HashMap<>(); 

    void put(MonthType month, TimeType time, Value value) { 
    Map<TimeType, Value> timeMap; 
    if (map.containsKey(month)) { 
     timeMap = map.get(month); 
    } else { 
     timeMap = new HashMap<>(); 
     map.put(month, timeMap); 
    } 
    timeMap.put(time, value); 
    } 

    Value get(MonthType month, TimeType time) { 
    if (!map.containsKey(month)) { 
     return null; 
    } 
    return map.get(month).get(time); 
    } 
} 
0

zrobię to w ten sposób zbyt, ale należy zachować ostrożność przy definiowaniu klucza danego HashMap: powinna być niezmienna, ponieważ w przeciwnym razie może to zagrozić zmienia mapowanie i hashowania i powinny implementować dwa wymagania klucza hash: hashCode i metody równe. coś takiego:

final class YourWrapper { 
    private final Integer month; 
    private final Integer time; 

    public YourWrapper(Integer month, Integer time) { 
     this.month = month; 
     this.time = time; 
    } 

    public Integer getMonth() { 
     return month; 
    } 

    public Integer getTime() { 
     return time; 
    } 

    @Override 
    public int hashCode() { 
     return month.hashCode()^time.hashCode(); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     return (obj instanceof YourWrapper) 
       && ((YourWrapper) obj).month.equals(month) 
       && ((YourWrapper) obj).time.equals(time); 
    } 
} 
0

Jeśli nie chcesz używać Mapa Map (niezbyt ładne, ale działa) wciąż masz kilka opcji ... na przykład przechowywania miesięcy i raz w łańcuchu , za pomocą czegoś podobnego DateFormat ds = new SimpleDateFormat(MM HH:mm:s), a następnie za pomocą konwertować obiekt Kalendarz wypełniony wartościami

Calendar cal = Calendar.getInstance(); 
cal.set(Calendar.MONTH, yourmonth); 
cal.set(Calendar.HOUR_OF_DAY, yourhours); 
cal.set(Calendar.MINUTE, yourminutes); 
cal.set(Calendar.SECOND, yoursecs); 
String val_to_store=ds.format(cal.getTime()); 

Albo, być może, można przechowywać obiekt kalendarza.

0

Doskonałe pytanie!

Przede wszystkim odpowiedź @dasblinkenlight jest prawidłowa, powiedzmy, przez większość czasu. Zbudowanie klucza pojedynczego obiektu jest najbardziej prostym i oczywistym rozwiązaniem. Jest to łatwe i jasne do zrozumienia i dość wydajne. Jeśli ta pamięć podręczna nie jest punktem dostępowym twojej aplikacji, nie musisz już więcej myśleć.

Istnieją jednak alternatywy, które mogą zapewnić lepszą wydajność.

Konceptualnie istnieją dwie możliwości:

  • skonstruować jeden kluczowy obiekt dla kluczy złożonych. To wspólny wzór i dość typowy, jeśli używasz kluczy złożonych do dostępu do bazy danych
  • zrobić dwa lub wielo poziomie hierarchicznym odnośnika, np store.get(month).get(time)

Dla hierarchicznej odnośnika, żaden dodatkowy przydział obiekt jest potrzebna, jednak zamienisz go na drugi dostęp do tablicy hash. Aby zachować maksymalną wydajność pamięci, ważne jest, aby najpierw umieścić klucz o najmniejszej przestrzeni wartości.

Jeśli to jest bardzo centralne miejsce swojego zastosowania, nawet lepszym rozwiązaniem jest umieszczenie pierwszego etapu przeglądową, dwanaście miesięcy, w tablicę i zainicjować go na starcie:

Cache<Time, Value>[] month2ValueCache = new Cache<Time, Value>[12]; 
{ 
    for (int i = 0; i < 12; i++) { 
    month2ValueCache[i] = new Cache<Time, Value>(...); 
    } 
} 
Value get(int month, Time, time) { 
    return month2ValueCache[month].get(time); 
} 

zrobiłem Benchmark porównawczy do formatowania dat za pomocą DateFromatter. To szwy podobne do twojego przypadku użycia. Ma to właściwie trzy kluczowe składniki: datę, format i lokalizację. Znajdziesz go tutaj: https://github.com/headissue/cache2k-benchmark/blob/master/zoo/src/test/java/org/cache2k/benchmark/DateFormattingBenchmark.java

Mój wynik był taki, że w rzeczywistości nie ma dużej różnicy czasu pomiędzy przydzieleniem obiektu dla kluczy złożonych lub trzema poziomami wyszukiwania pamięci podręcznej bez przydzielania obiektów dla klucza. Jednak zastosowana struktura porównawcza nie uwzględnia poprawnie zbierania śmieci. Po przejściu na inne środowisko testowe dokonam bardziej dogłębnej oceny.

Powiązane problemy