Sök…


Introduktion

Gränssnittet java.util.Map representerar en kartläggning mellan nycklar och deras värden. En karta kan inte innehålla duplikatnycklar; och varje knapp kan kartlägga till högst ett värde.

Eftersom Map är ett gränssnitt måste du anpassa en konkret implementering av det gränssnittet för att använda det; det finns flera Map , och mest används java.util.HashMap och java.util.TreeMap

Anmärkningar

En karta är ett objekt som lagrar nycklar med ett tillhörande värde för varje nyckel. En nyckel och dess värde kallas ibland ett nyckel- / värdepar eller en post . Kartor innehåller vanligtvis dessa funktioner:

  • Data lagras på kartan i nyckel- / värdepar.
  • Kartan kan innehålla endast en post för en viss nyckel. Om en karta innehåller en post med en viss nyckel och du försöker lagra en andra post med samma tangent kommer den andra posten att ersätta den första. Med andra ord kommer detta att ändra värdet som är associerat med nyckeln.
  • Kartor ger snabba funktioner för att testa om det finns en nyckel på kartan, för att hämta värdet som är associerat med en nyckel och ta bort ett nyckel- / värdepar.

Den mest använda kartimplementeringen är HashMap . Det fungerar bra med tangenter som är strängar eller siffror.

Vanliga kartor som HashMap är inte sorterade. Itertering genom nyckel- / värdepar kan returnera enskilda poster i valfri ordning. Om du måste upprepa kartposter på ett kontrollerat sätt bör du titta på följande:

  • Sorterade kartor som TreeMap uppdateras genom nycklar i deras naturliga ordning (eller i en ordning som du kan ange genom att tillhandahålla en komparator ). Exempelvis förväntas en sorterad karta med siffror som nycklar uppdateras genom dess poster i numerisk ordning.

  • LinkedHashMap tillåter iterering av poster i samma ordning som de sattes in på kartan, eller i den ordning som senast åtkomliga.

Lägg till ett element

  1. Tillägg
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element."); 
System.out.println(map.get(1));

Utgång: First element.

  1. Åsidosätta
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element.");
map.put(1, "New element.");
System.out.println(map.get(1));

Utgång: New element.

HashMap används som exempel. Andra implementationer som implementerar Map kan också användas.

Lägg till flera objekt

Vi kan använda V put(K key,V value) :

Kopplar det angivna värdet till den angivna nyckeln på den här kartan (valfri operation). Om kartan tidigare innehöll en mappning för nyckeln ersätts det gamla värdet av det angivna värdet.

String currentVal;
Map<Integer, String> map = new TreeMap<>();
currentVal = map.put(1, "First element.");
System.out.println(currentVal);// Will print null
currentVal = map.put(2, "Second element.");
System.out.println(currentVal); // Will print null yet again    
currentVal = map.put(2, "This will replace 'Second element'");
System.out.println(currentVal); // will print Second element.
System.out.println(map.size()); // Will print 2 as key having
// value 2 was replaced.

Map<Integer, String> map2 = new HashMap<>();
map2.put(2, "Element 2");
map2.put(3, "Element 3");

map.putAll(map2);

System.out.println(map.size());  

Produktion:

3

För att lägga till många objekt kan du använda en inre klasser som denna:

Map<Integer, String> map = new HashMap<>() {{
    // This is now an anonymous inner class with an unnamed instance constructor
    put(5, "high");
    put(4, "low");
    put(1, "too slow");
}};

Kom ihåg att det inte alltid är effektivt att skapa en anonym inre klass och kan leda till minnesläckor så använd ett initialiseringsblock istället:

static Map<Integer, String> map = new HashMap<>();

static {
    // Now no inner classes are created so we can avoid memory leaks
    put(5, "high");
    put(4, "low");
    put(1, "too slow");
}

Exemplet ovan gör kartan statisk. Det kan också användas i ett icke-statiskt sammanhang genom att ta bort alla static händelser.

Utöver det stöder de flesta implementeringar putAll , som kan lägga till alla poster på en karta till en annan som denna:

another.putAll(one);

Använda standardmetoder för kartor från Java 8

Exempel på att använda standardmetoder introducerade i Java 8 i kartgränssnittet

  1. Använda getOrDefault

Returnerar värdet som är mappat till nyckeln, eller om nyckeln inte finns, returnerar standardvärdet

Map<Integer, String> map = new HashMap<>();
map.put(1, "First element");
map.get(1);                                 // => First element
map.get(2);                                 // => null
map.getOrDefault(2, "Default element");     // => Default element
  1. Använda för varje

Gör det möjligt att utföra den åtgärd som anges i 'åtgärden' på varje kartinmatning

  Map<Integer, String> map = new HashMap<Integer, String>();
  map.put(1, "one");
  map.put(2, "two");
  map.put(3, "three");
  map.forEach((key, value) -> System.out.println("Key: "+key+ " :: Value: "+value));

   // Key: 1 :: Value: one
   // Key: 2 :: Value: two
   // Key: 3 :: Value: three
  1. Använda byta ut alla

Ersätter endast med nytt värde om nyckeln finns

 Map<String, Integer> map = new HashMap<String, Integer>();
 map.put("john", 20);
 map.put("paul", 30);
 map.put("peter", 40);
 map.replaceAll((key,value)->value+10);   //{john=30, paul=40, peter=50}
  1. Använda putIfAbsent

Key-Value-par läggs till på kartan om nyckeln inte finns eller mappas till null

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.putIfAbsent("kelly", 50);     //{john=20, paul=30, peter=40, kelly=50}
  1. Använd ta bort

    Tar bort nyckeln endast om den är associerad med det givna värdet

     Map<String, Integer> map = new HashMap<String, Integer>();
     map.put("john", 20);
     map.put("paul", 30);
     map.put("peter", 40);
     map.remove("peter",40); //{john=30, paul=40}
    
  2. Använd ersätt

    Om nyckeln finns, ersätts värdet med nytt värde. Om nyckeln inte finns, gör ingenting.

Map<String, Integer> map = new HashMap<String, Integer>();
map.put("john", 20);
map.put("paul", 30);
map.put("peter", 40);
map.replace("peter",50); //{john=20, paul=30, peter=50}
map.replace("jack",60); //{john=20, paul=30, peter=50}
  1. Använda computeIfAbsent

Den här metoden lägger till en post i kartan. nyckeln anges i funktionen och värdet är resultatet av tillämpningen av mappningsfunktionen

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.computeIfAbsent("kelly", k->map.get("john")+10); //{john=20, paul=30, peter=40, kelly=30}
    map.computeIfAbsent("peter", k->map.get("john")+10); //{john=20, paul=30, peter=40, kelly=30} //peter already present
  1. Med hjälp av computeIfPresent

Den här metoden lägger till en post eller modifierar en befintlig post på kartan. Gör ingenting om en post med den tangenten inte finns

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.computeIfPresent("kelly", (k,v)->v+10); //{john=20, paul=30, peter=40} //kelly not present
    map.computeIfPresent("peter", (k,v)->v+10); //{john=20, paul=30, peter=50} // peter present, so increase the value 
  1. Använda dator

Denna metod ersätter värdet på en nyckel med det nyberäknade värdet

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.compute("peter", (k,v)->v+50); //{john=20, paul=30, peter=90} //Increase the value 
  1. Med hjälp av sammanslagning

Lägger till nyckelvärdsparet på kartan, om nyckeln inte finns eller värdet för nyckeln är noll Byt ut värdet med det nyberäknade värdet, om nyckeln finns närvarande Nyckel tas bort från kartan, om beräknad nytt värde är noll

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    
    //Adds the key-value pair to the map, if key is not present or value for the key is null
    map.merge("kelly", 50 , (k,v)->map.get("john")+10); // {john=20, paul=30, peter=40, kelly=50}
    
    //Replaces the value with the newly computed value, if the key is present
    map.merge("peter", 50 , (k,v)->map.get("john")+10); //{john=20, paul=30, peter=30, kelly=50}
   
    //Key is removed from the map , if new value computed is null
    map.merge("peter", 30 , (k,v)->map.get("nancy")); //{john=20, paul=30, kelly=50}

Rensa kartan

Map<Integer, String> map = new HashMap<>();

map.put(1, "First element.");
map.put(2, "Second element.");
map.put(3, "Third element.");

map.clear();

System.out.println(map.size());   // => 0

Gör igenom innehållet på en karta

Kartor innehåller metoder som låter dig få åtkomst till nycklar, värden eller nyckelvärdespar på kartan som samlingar. Du kan iterera igenom dessa samlingar. Givet följande karta till exempel:

Map<String, Integer> repMap = new HashMap<>();
repMap.put("Jon Skeet", 927_654);
repMap.put("BalusC", 708_826);
repMap.put("Darin Dimitrov", 715_567);

Iterera genom kartnycklar:

for (String key : repMap.keySet()) {
    System.out.println(key);
}

Grafik:

Darin Dimitrov
Jon Skeet
BalusC

keySet() ger nycklarna på kartan som en Set . Set används eftersom tangenterna inte kan innehålla duplicerade värden. Iterering genom uppsättningen ger varje tangent i sin tur. HashMaps beställs inte, så i detta exempel kan nycklarna returneras i valfri ordning.

Iterating genom kartvärden:

for (Integer value : repMap.values()) {
    System.out.println(value);
}

Grafik:

715.567
927.654
708.826

values() returnerar värdena på kartan som en Collection . Iterating genom samlingen ger varje värde i sin tur. Återigen kan värdena returneras i valfri ordning.

Iterera genom nycklar och värden tillsammans

for (Map.Entry<String, Integer> entry : repMap.entrySet()) {
    System.out.printf("%s = %d\n", entry.getKey(), entry.getValue());
}

Grafik:

Darin Dimitrov = 715567
Jon Skeet = 927654
BalusC = 708826

entrySet() returnerar en samling Map.Entry objekt. Map.Entry ger åtkomst till nyckeln och värdet för varje post.

Slå samman, kombinera och komponera kartor

Använd putAll att lägga varje medlem på en karta till en annan. Nycklar som redan finns på kartan kommer att överskriva motsvarande värden.

Map<String, Integer> numbers = new HashMap<>();
numbers.put("One", 1)
numbers.put("Three", 3)
Map<String, Integer> other_numbers = new HashMap<>();
other_numbers.put("Two", 2)
other_numbers.put("Three", 4)

numbers.putAll(other_numbers)

Detta ger följande kartläggning i numbers :

"One" -> 1
"Two" -> 2
"Three" -> 4 //old value 3 was overwritten by new value 4

Om du vill kombinera värden istället för att skriva över dem, kan du använda Map.merge , tillagd i Java 8, som använder en användare som tillhandahålls BiFunction att slå samman värden för duplikatnycklar. merge fungerar med enskilda nycklar och värden, så du måste använda en slinga eller Map.forEach . Här sammanlänker vi strängar för duplikatnycklar:

for (Map.Entry<String, Integer> e : other_numbers.entrySet())
    numbers.merge(e.getKey(), e.getValue(), Integer::sum);
//or instead of the above loop
other_numbers.forEach((k, v) -> numbers.merge(k, v, Integer::sum));

Om du vill verkställa begränsningen finns det inga duplikatnycklar, du kan använda en sammanslagningsfunktion som kastar en AssertionError :

mapA.forEach((k, v) ->
    mapB.merge(k, v, (v1, v2) ->
        {throw new AssertionError("duplicate values for key: "+k);}));

Sammansätta karta <X, Y> och karta <Y, Z> för att få karta <X, Z>

Om du vill komponera två kartläggningar kan du göra det på följande sätt

    Map<String, Integer> map1 = new HashMap<String, Integer>();
    map1.put("key1", 1);
    map1.put("key2", 2);
    map1.put("key3", 3);
    
    Map<Integer, Double> map2 = new HashMap<Integer, Double>();
    map2.put(1, 1.0);
    map2.put(2, 2.0);
    map2.put(3, 3.0);

    Map<String, Double> map3 = new new HashMap<String, Double>();
    map1.forEach((key,value)->map3.put(key,map2.get(value)));

Detta ger följande kartläggning

    "key1" -> 1.0
    "key2" -> 2.0
    "key3" -> 3.0

Kontrollera om nyckeln finns

Map<String, String> num = new HashMap<>();
num.put("one", "first");

if (num.containsKey("one")) {
    System.out.println(num.get("one")); // => first
}

Kartor kan innehålla nollvärden

För kartor måste man vara försiktig så att man inte förväxlar ”som innehåller en nyckel” med ”att ha ett värde”. HashMap kan till exempel innehålla null vilket innebär att följande är helt normalt beteende:

Map<String, String> map = new HashMap<>();
map.put("one", null);
if (map.containsKey("one")) {
    System.out.println("This prints !"); // This line is reached 
}
if (map.get("one") != null) {
    System.out.println("This is never reached !"); // This line is never reached 
}

Mer formellt finns det ingen garanti för att map.contains(key) <=> map.get(key)!=null

Iterera kartposter effektivt

Detta avsnitt tillhandahåller kod och riktmärken för tio unika exempelimplementeringar som upprepas över posten på en Map<Integer, Integer> och genererar summan av Integer . Alla exemplen har en algoritmisk komplexitet på Θ(n) , men riktmärkena är fortfarande användbara för att ge insikt om vilka implementeringar som är mer effektiva i en "verklig värld" miljö.

  1. Implementering med Iterator med Map.Entry
    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<Integer, Integer> pair = it.next();
        sum += pair.getKey() + pair.getValue();
    }
  1. Implementering med for med Map.Entry
    for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
        sum += pair.getKey() + pair.getValue();
    }
  1. Implementering med Map.forEach (Java 8+)
    map.forEach((k, v) -> sum[0] += k + v);
  1. Implementering med Map.keySet med for
    for (Integer key : map.keySet()) {
        sum += key + map.get(key);
    }
  1. Implementering med Map.keySet med Iterator
    Iterator<Integer> it = map.keySet().iterator();
    while (it.hasNext()) {
        Integer key = it.next();
        sum += key + map.get(key);
    }
  1. Implementering med for Iterator och Map.Entry
    for (Iterator<Map.Entry<Integer, Integer>> entries = 
             map.entrySet().iterator(); entries.hasNext(); ) {
        Map.Entry<Integer, Integer> entry = entries.next();
        sum += entry.getKey() + entry.getValue();
    }
  1. Implementering med Stream.forEach (Java 8+)
    map.entrySet().stream().forEach(e -> sum += e.getKey() + e.getValue());
  1. Implementering med Stream.forEach med Stream.parallel (Java 8+)
    map.entrySet()
       .stream()
       .parallel()
       .forEach(e -> sum += e.getKey() + e.getValue());
  1. Implementering med IterableMap från Apache Collections
    MapIterator<Integer, Integer> mit = iterableMap.mapIterator();
    while (mit.hasNext()) {
        sum += mit.next() + it.getValue();
    }
  1. Implementering med hjälp av MutableMap från Eclipse Collections
     mutableMap.forEachKeyValue((key, value) -> {
         sum += key + value;
     });

Prestandatester ( kod tillgänglig på Github )
Testmiljö: Windows 8.1 64-bitars, Intel i7-4790 3.60GHz, 16 GB

  1. Genomsnittlig prestanda på 10 försök (100 element) Bäst: 308 ± 21 ns / op

    Benchmark                           Score     Error  Units
    test3_UsingForEachAndJava8            308  ±     21  ns/op
    test10_UsingEclipseMutableMap         309  ±      9  ns/op
    test1_UsingWhileAndMapEntry           380  ±     14  ns/op
    test6_UsingForAndIterator             387  ±     16  ns/op
    test2_UsingForEachAndMapEntry         391  ±     23  ns/op
    test7_UsingJava8StreamAPI             510  ±     14  ns/op
    test9_UsingApacheIterableMap          524  ±      8  ns/op
    test4_UsingKeySetAndForEach           816  ±     26  ns/op
    test5_UsingKeySetAndIterator          863  ±     25  ns/op
    test8_UsingJava8StreamAPIParallel    5552  ±    185  ns/op
    
  2. Genomsnittlig prestanda på 10 försök (10000 element) Bäst: 37,606 ± 0,790 μs / op

    Benchmark                           Score     Error  Units
    test10_UsingEclipseMutableMap       37606  ±    790  ns/op
    test3_UsingForEachAndJava8          50368  ±    887  ns/op
    test6_UsingForAndIterator           50332  ±    507  ns/op
    test2_UsingForEachAndMapEntry       51406  ±   1032  ns/op
    test1_UsingWhileAndMapEntry         52538  ±   2431  ns/op
    test7_UsingJava8StreamAPI           54464  ±    712  ns/op
    test4_UsingKeySetAndForEach         79016  ±  25345  ns/op
    test5_UsingKeySetAndIterator        91105  ±  10220  ns/op
    test8_UsingJava8StreamAPIParallel  112511  ±    365  ns/op
    test9_UsingApacheIterableMap       125714  ±   1935  ns/op
    
  3. Genomsnittlig prestanda på 10 försök (100000 element) Bäst: 1184,767 ± 332,968 μs / op

    Benchmark                            Score       Error  Units
    test1_UsingWhileAndMapEntry       1184.767  ±  332.968  μs/op
    test10_UsingEclipseMutableMap     1191.735  ±  304.273  μs/op
    test2_UsingForEachAndMapEntry     1205.815  ±  366.043  μs/op
    test6_UsingForAndIterator         1206.873  ±  367.272  μs/op
    test8_UsingJava8StreamAPIParallel 1485.895  ±  233.143  μs/op
    test5_UsingKeySetAndIterator      1540.281  ±  357.497  μs/op
    test4_UsingKeySetAndForEach       1593.342  ±  294.417  μs/op
    test3_UsingForEachAndJava8        1666.296  ±  126.443  μs/op
    test7_UsingJava8StreamAPI         1706.676  ±  436.867  μs/op
    test9_UsingApacheIterableMap      3289.866  ± 1445.564  μs/op
    
  4. En jämförelse av prestationsvariationer med avseende på kartans storlek

Graf över prestandatester

       x: Size of Map
    f(x): Benchmark Score (μs/op)

                 100      600     1100     1600     2100
        ---------------------------------------------------
        10  |   0.333    1.631    2.752    5.937    8.024
         3  |   0.309    1.971    4.147    8.147   10.473
         6  |   0.372    2.190    4.470    8.322   10.531
         1  |   0.405    2.237    4.616    8.645   10.707
Tests    2  |   0.376    2.267    4.809    8.403   10.910
 f(x)    7  |   0.473    2.448    5.668    9.790   12.125
         9  |   0.565    2.830    5.952    13.22   16.965
         4  |   0.808    5.012    8.813    13.939  17.407
         5  |   0.81     5.104    8.533    14.064  17.422
         8  |   5.173   12.499   17.351    24.671  30.403

Använd anpassat objekt som nyckel

Innan du använder ditt eget objekt som nyckel måste du åsidosätta metoden hashCode () och equals () för ditt objekt.

I enkla fall skulle du ha något som:

class MyKey {
    private String name;
    MyKey(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {            
        if(obj instanceof MyKey) {
            return this.name.equals(((MyKey)obj).name);
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        return this.name.hashCode();
    }
}

hashCode avgör vilken hash-skopa nyckeln tillhör och equals kommer att bestämma vilket objekt inuti det hash-skopan.

Utan denna metod kommer referensen till ditt objekt att användas för jämförelse ovan som inte fungerar om du inte använder samma objektreferens varje gång.

Användning av HashMap

HashMap är en implementering av kartgränssnittet som tillhandahåller en datastruktur för att lagra data i nyckelvärdespar.

1. Förklara HashMap

Map<KeyType, ValueType> myMap = new HashMap<KeyType, ValueType>();

KeyType och ValueType måste vara giltiga typer i Java, till exempel - String, heltal, Float eller någon anpassad klass som anställd, student osv.

Till exempel: Map<String,Integer> myMap = new HashMap<String,Integer>();

2. Lägga värden i HashMap.

För att sätta ett värde i HashMap, måste vi anropa put metoden på HashMap-objektet genom att lämna nyckeln och värdet som parametrar.

myMap.put("key1", 1);
myMap.put("key2", 2);

Om du kallar put-metoden med nyckeln som redan finns på kartan, kommer metoden att åsidosätta dess värde och returnera det gamla värdet.

3. Få värden från HashMap.

För att få värdet från en HashMap måste du anropa get metoden genom att lämna nyckeln som en parameter.

myMap.get("key1");    //return 1 (class Integer)

Om du passerar en nyckel som inte finns i HashMap kommer denna metod att returnera null

4. Kontrollera om nyckeln finns på kartan eller inte.

myMap.containsKey(varKey);

5. Kontrollera om värdet finns på kartan eller inte.

myMap.containsValue(varValue);

Ovanstående metoder kommer att returnera ett boolean värde sant eller falskt om nyckel, värde finns på kartan eller inte.

Skapa och initiera kartor

Introduktion

Maps lagrar nyckel- / värdepar, där varje nyckel har ett tillhörande värde. Med en viss nyckel kan kartan slå upp det tillhörande värdet mycket snabbt.

Maps , även känd som associerad matris, är ett objekt som lagrar data i form av nycklar och värden. I Java representeras kartor med hjälp av kartgränssnitt som inte är en förlängning av samlingsgränssnittet.

  • Väg 1: -

     /*J2SE < 5.0*/
     Map map = new HashMap();
     map.put("name", "A");
     map.put("address", "Malviya-Nagar");
     map.put("city", "Jaipur");
     System.out.println(map);
    
  • Väg 2: -

     /*J2SE 5.0+ style (use of generics):*/
     Map<String, Object> map = new HashMap<>();
     map.put("name", "A");
     map.put("address", "Malviya-Nagar");
     map.put("city", "Jaipur");
     System.out.println(map);
    
  • Väg 3: -

      Map<String, Object> map = new HashMap<String, Object>(){{
          put("name", "A");
          put("address", "Malviya-Nagar");
          put("city", "Jaipur");
      }};
      System.out.println(map);
    
  • Väg 4: -

      Map<String, Object> map = new TreeMap<String, Object>();
          map.put("name", "A");
          map.put("address", "Malviya-Nagar");
          map.put("city", "Jaipur");
      System.out.println(map);
    
  • Väg 5: -

      //Java 8
      final Map<String, String> map =
          Arrays.stream(new String[][] {
              { "name", "A" }, 
              { "address", "Malviya-Nagar" }, 
              { "city", "jaipur" },
          }).collect(Collectors.toMap(m -> m[0], m -> m[1]));
      System.out.println(map);
    
  • Väg 6: -

      //This way for initial a map in outside the function
      final static Map<String, String> map;
      static
      {
          map = new HashMap<String, String>();
          map.put("a", "b");
          map.put("c", "d");
      }
    
  • Sätt 7: - Skapa en immutable karta med en enda nyckelvärde.

        //Immutable single key-value map
        Map<String, String> singletonMap = Collections.singletonMap("key", "value");
    

    Observera att det är omöjligt att ändra en sådan karta .

    Eventuella ändringar för att ändra kartan kommer att leda till att UnsupportedOperationException kastas.

        //Immutable single key-value pair
        Map<String, String> singletonMap = Collections.singletonMap("key", "value");
        singletonMap.put("newKey", "newValue"); //will throw UnsupportedOperationException
        singletonMap.putAll(new HashMap<>()); //will throw UnsupportedOperationException
        singletonMap.remove("key"); //will throw UnsupportedOperationException
        singletonMap.replace("key", "value", "newValue"); //will throw UnsupportedOperationException
        //and etc
    


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow