2012-11-18 14 views
10

Devo creare un valore statico Map che associa un dato String a un array di int.Come creare una mappa statica di stringhe -> Array

In altre parole, mi piacerebbe definire qualcosa di simile:

"fred" -> {1,2,5,8} 
"dave" -> {5,6,8,10,11} 
"bart" -> {7,22,10010} 
... etc 

C'è un modo semplice per fare questo in Java?

E se possibile, mi piacerebbe utilizzare le costanti static per entrambi i valori String e int.

EDIT: chiarire che cosa volevo dire con static costanti per i valori, e per dare quello che vedo essere il codice corretto, ecco il mio primo tentativo di soluzione:

public final static String FRED_TEXT = "fred"; 
public final static String DAVE_TEXT = "dave"; 

public final static int ONE = 1; 
public final static int TWO = 2; 
public final static int THREE = 3; 
public final static int FOUR = 4; 

public final static HashMap<String, int[]> myMap = new HashMap<String, int[]>(); 
static { 
    myMap.put(FRED_TEXT, new int[] {ONE, TWO, FOUR}); 
    myMap.put(DAVE_TEXT, new int[] {TWO, THREE}); 
} 

nota, questi nomi non sono quelli che effettivamente userò. Questo è solo un esempio forzato.

risposta

21

È non necessario separare la dichiarazione e l'inizializzazione. Se sai come, tutto può essere fatto in un'unica riga!

// assumes your code declaring the constants ONE, FRED_TEXT etc is before this line 
private static final Map<String, int[]> myMap = Collections.unmodifiableMap(
    new HashMap<String, int[]>() {{ 
     put(FRED_TEXT, new int[] {ONE, TWO, FOUR}); 
     put(DAVE_TEXT, new int[] {TWO, THREE}); 
    }}); 

Quello che abbiamo qui è una classe anonima con una inialization block - un blocco di codice che viene eseguito in costruzione dopo la costruzione, che abbiamo utilizzato qui per caricare la mappa (questo è a volte erroneamente conosciuto come "doppio brace inizializzazione "- Suppongo perché ci sono due parentesi adiacenti = ma in realtà non esiste nulla di simile).

Le due cose interessanti di questo sono a) si sposa la dichiarazione con il contenuto eb) perché l'inizializzazione è in linea, è anche possibile effettuare una chiamata in linea a Collections.unmodifiableMap(), risultante in una riga semplice dichiarazione, inizializzazione e conversione a non modificabile.

Se non avete bisogno/vogliono la mappa per essere immodificabile, lasciare fuori quella chiamata:

private static final Map<String, int[]> myMap = new HashMap<String, int[]>() {{ 
    put(FRED_TEXT, new int[] {ONE, TWO, FOUR}); 
    put(DAVE_TEXT, new int[] {TWO, THREE}); 
}}; 
+0

Ah, ma ho bisogno di dichiarare la mappa in una super classe, ma di popolarla in una sottoclasse. Scusa, so che non era nella mia domanda iniziale. Avrei ancora bisogno del blocco 'static' in questo caso? – DuncanKinnear

+0

Ma poiché questo è 'statico', come può essere" un blocco di codice che viene eseguito in costruzione dopo il costruttore "? Ho pensato che la costruzione non si verifica quando si fa riferimento al codice 'static'. – DuncanKinnear

+1

@DuncanKinnear l'istanza è statica, ma il blocco no. Il blocco è un blocco di istanza della classe anonima che viene istanziato staticamente. La classe anonima è una sottoclasse di 'HashMap', di cui esiste sempre una sola istanza (' new' viene chiamata una sola volta) – Bohemian

1
static Map<String, int[]> map = new HashMap<>(); 

La mappa è statico, è possibile accedervi senza creare un'istanza della classe è definito. Non so cosa intendi con avere le chiavi e valori statici pure, perché non ha senso per me.

+0

Vedere la mia modifica per un esempio di utilizzo delle costanti statiche. – DuncanKinnear

5

È necessario dichiarare e inizializzare la mappa statica separatamente.

Ecco il pezzo dichiarazione:

private static final Map<String,int[]> MyMap; 

Ecco il pezzo di inizializzazione:

static { 
    Map<String,int[]> tmpMap = new HashMap<String,int[]>(); 
    tmpMap.put("fred", new int[] {1,2,5,8}); 
    tmpMap.put("dave", new int[] {5,6,8,10,11}); 
    tmpMap.put("bart", new int[] {7,22,10010}); 
    MyMap = Collections.unmodifiableMap(tmpMap); 
} 

Purtroppo, gli array sono sempre scrivibile in Java. Non sareste in grado di assegnare MyMap, ma sareste in grado di aggiungere o rimuovere valori da altre parti del programma che accedono alla mappa.

+1

+1 per blocco inizializzatore statico – jlordo

+1

Naturalmente, la mappa e gli array saranno entrambi scrivibili in questo esempio. – cdhowie

+0

@cdhowie Hai ragione, ho aggiunto un paragrafo alla risposta per sottolineare questo punto. – dasblinkenlight

0
public class ExampleClass { 
    public final static HashMap consts = new HashMap(); 
    static 
    { 
     constants.put("A", "The Letter A"); 
     constants.put("B", "The Letter B"); 
     constants.put("C", "The Letter C"); 
    } 
    /* Rest of your class that needs to know the consts */ 
} 
+0

Correggetemi se ho torto, ma il blocco statico viene eseguito prima dell'inizializzazione di "consts" giusto? –

+0

Ho provato e qualsiasi cosa tu abbia scritto è corretta. Ma se commutiamo il blocco di inizializzazione dei conts e il blocco statico, verrà generato un errore di compilazione. Non ho mai pensato che l'ordine di definire gli elementi avrebbe avuto alcun effetto in Java. –

5

Per ragioni di completezza in quanto questo è il primo risultato di Google per 'java static definire la mappa 'In Java 8 ora puoi farlo.

Collections.unmodifiableMap(Stream.of(
      new SimpleEntry<>("a", new int[]{1,2,3}), 
      new SimpleEntry<>("b", new int[]{1,2,3}), 
      new SimpleEntry<>("c", new int[]{1,2,3})) 
      .collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()))); 

Questa bella parte di questo è che non stiamo creando più classi anonime con la sintassi doppia parentesi graffa ({{ }})

Possiamo quindi estendere questo con un po 'di codice per ripulire il modello come questo ragazzo fatto qui http://minborgsjavapot.blogspot.ca/2014/12/java-8-initializing-maps-in-smartest-way.html

public static <K, V> Map.Entry<K, V> entry(K key, V value) { 
    return new AbstractMap.SimpleEntry<>(key, value); 
} 

public static <K, U> Collector<Map.Entry<K, U>, ?, Map<K, U>> entriesToMap() { 
    return Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()); 
} 

public static <K, U> Collector<Map.Entry<K, U>, ?, ConcurrentMap<K, U>> entriesToConcurrentMap() { 
    return Collectors.toConcurrentMap((e) -> e.getKey(), (e) -> e.getValue()); 
} 

risultato finale

Collections.unmodifiableMap(Stream.of(
      entry("a", new int[]{1,2,3}), 
      entry("b", new int[]{1,2,3}), 
      entry("c", new int[]{1,2,3})) 
      .collect(entriesToMap())); 

che ci fornirebbe una mappa non modificabile simultanea.

+0

Grazie per la risposta. Peccato che siamo bloccati su Java 6. – DuncanKinnear

Problemi correlati