Java Language
Kartor
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
- Tillägg
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element.");
System.out.println(map.get(1));
Utgång: First element.
- Å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
- 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
- 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
- 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}
- 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}
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}
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}
- 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
- 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
- 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
- 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ö.
Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, Integer> pair = it.next();
sum += pair.getKey() + pair.getValue();
}
for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
sum += pair.getKey() + pair.getValue();
}
- Implementering med
Map.forEach
(Java 8+)
map.forEach((k, v) -> sum[0] += k + v);
- Implementering med
Map.keySet
medfor
for (Integer key : map.keySet()) {
sum += key + map.get(key);
}
- Implementering med
Map.keySet
medIterator
Iterator<Integer> it = map.keySet().iterator();
while (it.hasNext()) {
Integer key = it.next();
sum += key + map.get(key);
}
for (Iterator<Map.Entry<Integer, Integer>> entries =
map.entrySet().iterator(); entries.hasNext(); ) {
Map.Entry<Integer, Integer> entry = entries.next();
sum += entry.getKey() + entry.getValue();
}
- Implementering med
Stream.forEach
(Java 8+)
map.entrySet().stream().forEach(e -> sum += e.getKey() + e.getValue());
- Implementering med
Stream.forEach
medStream.parallel
(Java 8+)
map.entrySet()
.stream()
.parallel()
.forEach(e -> sum += e.getKey() + e.getValue());
- Implementering med
IterableMap
från Apache Collections
MapIterator<Integer, Integer> mit = iterableMap.mapIterator();
while (mit.hasNext()) {
sum += mit.next() + it.getValue();
}
- 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
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
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
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
En jämförelse av prestationsvariationer med avseende på kartans storlek
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