Jak sprawnie iterować każdy wpis na mapie Javy?
Jeśli mam obiekt implementujący interfejs Map
w Javie i chcę iterację nad każdą parą w nim zawartą, jaki jest najbardziej efektywny sposób przechodzenia przez mapę?
Czy kolejność elementów zależy od konkretnej implementacji mapy, którą mam dla interfejsu?
30 answers
Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + "/" + entry.getValue());
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-14 22:20:24
Aby podsumować Pozostałe odpowiedzi i połączyć je z tym, co wiem, znalazłem 10 głównych sposobów, aby to zrobić (patrz poniżej). Napisałem też kilka testów wydajnościowych(patrz wyniki poniżej). Na przykład, jeśli chcemy znaleźć sumę wszystkich kluczy i wartości mapy, możemy napisać:
-
Za pomocą iteratora i Mapy.Wpis
long i = 0; Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Integer, Integer> pair = it.next(); i += pair.getKey() + pair.getValue(); }
-
Używając foreach i Mapy.Wpis
long i = 0; for (Map.Entry<Integer, Integer> pair : map.entrySet()) { i += pair.getKey() + pair.getValue(); }
-
Using forEach from Java 8
final long[] i = {0}; map.forEach((k, v) -> i[0] += k + v);
-
Using keySet and foreach
long i = 0; for (Integer key : map.keySet()) { i += key + map.get(key); }
-
Using keySet and iterator
long i = 0; Iterator<Integer> itr2 = map.keySet().iterator(); while (itr2.hasNext()) { Integer key = itr2.next(); i += key + map.get(key); }
-
Używając dla i Mapy.Wpis
long i = 0; for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<Integer, Integer> entry = entries.next(); i += entry.getKey() + entry.getValue(); }
-
Korzystanie z Java 8 Stream API
final long[] i = {0}; map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
-
Korzystanie z Java 8 Stream API parallel
final long[] i = {0}; map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());
-
Using IterableMap of
Apache Collections
long i = 0; MapIterator<Integer, Integer> it = iterableMap.mapIterator(); while (it.hasNext()) { i += it.next() + it.getValue(); }
-
Użycie MutableMap kolekcji Eclipse (CS)
final long[] i = {0}; mutableMap.forEachKeyValue((key, value) -> { i[0] += key + value; });
Testy wydajności (mode = AverageTime, system = Windows 8.1 64-bit, Intel i7 - 4790 3.60 GHz, 16 GB)
-
Dla małej mapy (100 elementów) wynik 0,308 jest najlepszy
Benchmark Mode Cnt Score Error Units test3_UsingForEachAndJava8 avgt 10 0.308 ± 0.021 µs/op test10_UsingEclipseMap avgt 10 0.309 ± 0.009 µs/op test1_UsingWhileAndMapEntry avgt 10 0.380 ± 0.014 µs/op test6_UsingForAndIterator avgt 10 0.387 ± 0.016 µs/op test2_UsingForEachAndMapEntry avgt 10 0.391 ± 0.023 µs/op test7_UsingJava8StreamApi avgt 10 0.510 ± 0.014 µs/op test9_UsingApacheIterableMap avgt 10 0.524 ± 0.008 µs/op test4_UsingKeySetAndForEach avgt 10 0.816 ± 0.026 µs/op test5_UsingKeySetAndIterator avgt 10 0.863 ± 0.025 µs/op test8_UsingJava8StreamApiParallel avgt 10 5.552 ± 0.185 µs/op
-
Dla mapy z 10000 elementów, wynik 37.606 jest najlepszy
Benchmark Mode Cnt Score Error Units test10_UsingEclipseMap avgt 10 37.606 ± 0.790 µs/op test3_UsingForEachAndJava8 avgt 10 50.368 ± 0.887 µs/op test6_UsingForAndIterator avgt 10 50.332 ± 0.507 µs/op test2_UsingForEachAndMapEntry avgt 10 51.406 ± 1.032 µs/op test1_UsingWhileAndMapEntry avgt 10 52.538 ± 2.431 µs/op test7_UsingJava8StreamApi avgt 10 54.464 ± 0.712 µs/op test4_UsingKeySetAndForEach avgt 10 79.016 ± 25.345 µs/op test5_UsingKeySetAndIterator avgt 10 91.105 ± 10.220 µs/op test8_UsingJava8StreamApiParallel avgt 10 112.511 ± 0.365 µs/op test9_UsingApacheIterableMap avgt 10 125.714 ± 1.935 µs/op
-
Dla mapy z 100000 elementów, wynik 1184.767 jest the best
Benchmark Mode Cnt Score Error Units test1_UsingWhileAndMapEntry avgt 10 1184.767 ± 332.968 µs/op test10_UsingEclipseMap avgt 10 1191.735 ± 304.273 µs/op test2_UsingForEachAndMapEntry avgt 10 1205.815 ± 366.043 µs/op test6_UsingForAndIterator avgt 10 1206.873 ± 367.272 µs/op test8_UsingJava8StreamApiParallel avgt 10 1485.895 ± 233.143 µs/op test5_UsingKeySetAndIterator avgt 10 1540.281 ± 357.497 µs/op test4_UsingKeySetAndForEach avgt 10 1593.342 ± 294.417 µs/op test3_UsingForEachAndJava8 avgt 10 1666.296 ± 126.443 µs/op test7_UsingJava8StreamApi avgt 10 1706.676 ± 436.867 µs/op test9_UsingApacheIterableMap avgt 10 3289.866 ± 1445.564 µs/op
Wykresy (testy wydajności w zależności od wielkości mapy)
Tabela (testy wydajności w zależności od wielkości mapy)
100 600 1100 1600 2100
test10 0.333 1.631 2.752 5.937 8.024
test3 0.309 1.971 4.147 8.147 10.473
test6 0.372 2.190 4.470 8.322 10.531
test1 0.405 2.237 4.616 8.645 10.707
test2 0.376 2.267 4.809 8.403 10.910
test7 0.473 2.448 5.668 9.790 12.125
test9 0.565 2.830 5.952 13.220 16.965
test4 0.808 5.012 8.813 13.939 17.407
test5 0.810 5.104 8.533 14.064 17.422
test8 5.173 12.499 17.351 24.671 30.403
Wszystkie testy są na GitHub .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-05 20:12:22
W Javie 8 możesz to zrobić czysto i szybko, korzystając z nowych funkcji lambda:
Map<String,String> map = new HashMap<>();
map.put("SomeKey", "SomeValue");
map.forEach( (k,v) -> [do something with key and value] );
// such as
map.forEach( (k,v) -> System.out.println("Key: " + k + ": Value: " + v));
Typ k
i v
zostanie wywnioskowany przez kompilator i nie ma już potrzeby używania Map.Entry
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-07 08:33:17
Tak, kolejność zależy od konkretnej implementacji Mapy.
@ScArcher2 posiada bardziej elegancką składnię Java 1.5 . W 1.4 zrobiłbym coś takiego:
Iterator entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
Entry thisEntry = (Entry) entries.next();
Object key = thisEntry.getKey();
Object value = thisEntry.getValue();
// ...
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-06 22:32:29
Typowy kod do iteracji na mapie to:
Map<String,Thing> map = ...;
for (Map.Entry<String,Thing> entry : map.entrySet()) {
String key = entry.getKey();
Thing thing = entry.getValue();
...
}
HashMap
jest kanoniczną implementacją map i nie daje gwarancji (lub chociaż nie powinna zmieniać kolejności, jeśli na niej nie są wykonywane żadne operacje mutacyjne). SortedMap
zwróci wpisy w oparciu o naturalną kolejność kluczy, lub Comparator
, jeśli jest to przewidziane. LinkedHashMap
zwróci wpisy w kolejności wstawiania lub w kolejności dostępu w zależności od sposobu ich budowy. EnumMap
zwraca wpisy w naturalnej kolejności klucze.
(Aktualizacja: myślę, że to już nie jest prawda.) uwaga, IdentityHashMap
entrySet
iterator posiada obecnie osobliwą implementację, która zwraca tę samą instancję Map.Entry
dla każdego elementu w entrySet
! Jednak za każdym razem, gdy nowy iterator awansuje Map.Entry
jest aktualizowany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-09 01:11:36
Przykład użycia iteratora i generyków:
Iterator<Map.Entry<String, String>> entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, String> entry = entries.next();
String key = entry.getKey();
String value = entry.getValue();
// ...
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-18 17:34:51
Jest to pytanie dwuczęściowe:
Jak iterować nad wpisami na mapie - @ ScArcher2 odpowiedział że doskonale.
Jaka jest kolejność iteracji - jeśli używasz tylko Map
, to ściśle mówiąc, nie ma żadnych gwarancji porządkowania . Więc tak naprawdę nie powinieneś polegać na zamówieniu podanym przez jakąkolwiek realizację. Jednak SortedMap
interfejs rozszerza Map
i zapewnia dokładnie to, czego szukasz - implementacje dadzą spójną kolejność sortowania.
NavigableMap
jest kolejnym przydatnym rozszerzeniem - jest to SortedMap
z dodatkowymi metodami znajdowania wpisów według ich uporządkowanej pozycji w zestawie kluczy. Więc potencjalnie może to usunąć potrzebę iteracji w pierwszej kolejności - możesz być w stanie znaleźć konkretny entry
, który jesteś po użyciu higherEntry
, lowerEntry
, ceilingEntry
, lub floorEntry
metody. Metoda descendingMap
daje nawet jawną metodę odwracania kolejność przejazdu .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:32
Jest kilka sposobów na iterację mapy.
Oto porównanie ich wydajności dla wspólnego zestawu danych przechowywanych w map przez przechowywanie milionów par wartości klucza w map i będzie iteracją ponad mapą.
1) Użycie entrySet()
in dla każdej pętli
for (Map.Entry<String,Integer> entry : testMap.entrySet()) {
entry.getKey();
entry.getValue();
}
50 milisekundy
2) Użycie keySet()
in dla każdej pętli
for (String key : testMap.keySet()) {
testMap.get(key);
}
76 milisekundy
3) Używanie entrySet()
i iteratora
Iterator<Map.Entry<String,Integer>> itr1 = testMap.entrySet().iterator();
while(itr1.hasNext()) {
Map.Entry<String,Integer> entry = itr1.next();
entry.getKey();
entry.getValue();
}
50 milisekundy
4) Używanie keySet()
i iteratora
Iterator itr2 = testMap.keySet().iterator();
while(itr2.hasNext()) {
String key = itr2.next();
testMap.get(key);
}
75 milisekundy
Odnieśli this link
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-18 15:58:26
Poprawnym sposobem, aby to zrobić, jest użycie zaakceptowanej odpowiedzi, ponieważ jest ona najbardziej skuteczna. Uważam, że poniższy kod wygląda nieco czystsze.
for (String key: map.keySet()) {
System.out.println(key + "/" + map.get(key));
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-17 00:16:44
Dla twojej wiadomości, możesz również użyć map.keySet()
i map.values()
jeśli interesują Cię tylko klucze/wartości mapy, a nie inne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-05 22:27:52
Za pomocą Java 8 można iterować mapę używając wyrażenia forEach i lambda,
map.forEach((k, v) -> System.out.println((k + ":" + v)));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-15 09:09:30
Z kolekcjami Eclipse , można użyć metody forEachKeyValue
na MapIterable
interfejs, który jest dziedziczony przez interfejsy MutableMap
i ImmutableMap
i ich implementacje.
MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue((key, value) -> result.add(key + value));
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);
Używając anonimowej klasy wewnętrznej, możesz napisać kod w następujący sposób:
final MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue(new Procedure2<Integer, String>()
{
public void value(Integer key, String value)
{
result.add(key + value);
}
});
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);
Notatka: jestem committerem Dla Kolekcji Eclipse.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-13 19:49:46
W teorii, najbardziej efektywny sposób będzie zależał od tego, która implementacja Mapy. Oficjalnym sposobem na to jest wywołanie map.entrySet()
, które zwraca zbiór Map.Entry
, z których każdy zawiera klucz i wartość (entry.getKey()
i entry.getValue()
).
W idiosynkratycznej implementacji może mieć znaczenie, czy używasz map.keySet()
, map.entrySet()
albo coś innego. Ale nie mogę wymyślić powodu, dla którego ktoś miałby to tak pisać. Najprawdopodobniej nie ma różnicy w wydajności tego, co robisz.
I tak, kolejność będzie zależeć od implementacji - a także (ewentualnie) kolejności wstawiania i innych trudnych do kontrolowania czynników.
[edytuj] pisałem valueSet()
pierwotnie, ale oczywiście entrySet()
jest właściwie odpowiedzią.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-04 22:39:46
Lambda Wyrażenie Java 8
W Javie 1.8 (Java 8) stało się to znacznie łatwiejsze dzięki zastosowaniu metody forEach z operacji Agregacyjnych (Stream operations), która wygląda podobnie do iteratorów z interfejsu Iterable.
Po prostu skopiuj wklej poniższą instrukcję do kodu i zmień nazwę zmiennej HashMap z hm na zmienną HashMap, aby wydrukować parę klucz-wartość.
HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
/*
* Logic to put the Key,Value pair in your HashMap hm
*/
// Print the key value pair in one line.
hm.forEach((k, v) -> System.out.println("key: " + k + " value:" + v));
// Just copy and paste above line to your code.
Poniżej znajduje się przykładowy kod, który próbowałem używając wyrażenia Lambda. To jest takie fajne. Muszę spróbować.
HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
Random rand = new Random(47);
int i = 0;
while(i < 5) {
i++;
int key = rand.nextInt(20);
int value = rand.nextInt(50);
System.out.println("Inserting key: " + key + " Value: " + value);
Integer imap = hm.put(key, value);
if( imap == null) {
System.out.println("Inserted");
} else {
System.out.println("Replaced with " + imap);
}
}
hm.forEach((k, v) -> System.out.println("key: " + k + " value:" + v));
Output:
Inserting key: 18 Value: 5
Inserted
Inserting key: 13 Value: 11
Inserted
Inserting key: 1 Value: 29
Inserted
Inserting key: 8 Value: 0
Inserted
Inserting key: 2 Value: 7
Inserted
key: 1 value:29
key: 18 value:5
key: 2 value:7
key: 8 value:0
key: 13 value:11
Również można użyć Spliterator do tego samego.
Spliterator sit = hm.entrySet().spliterator();
UPDATE
Wraz z odnośnikami do dokumentacji Oracle Docs. Aby dowiedzieć się więcej o Lambda wejdź w ten link i przeczytaj operacje zbiorcze , A Dla Spliteratora przejdź do tego link .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-30 13:05:59
Java 8
Mamy metodę forEach
, która przyjmuje wyrażenie lambda. Mamy również API stream. Rozważmy mapę:
Map<String,String> sample = new HashMap<>();
sample.put("A","Apple");
sample.put("B", "Ball");
Iteracja nad kluczami:
sample.keySet().forEach((k) -> System.out.println(k));
Iteracja nad wartościami:
sample.values().forEach((v) -> System.out.println(v));
Iteracja nad wpisami (za pomocą forEach i strumieni):
sample.forEach((k,v) -> System.out.println(k + ":" + v));
sample.entrySet().stream().forEach((entry) -> {
Object currentKey = entry.getKey();
Object currentValue = entry.getValue();
System.out.println(currentKey + ":" + currentValue);
});
Zaletą strumieni jest to, że mogą być łatwo równoległe w przypadku, gdy chcemy. Po prostu musimy użyć parallelStream()
zamiast stream()
powyżej.
forEachOrdered
vs forEach
ze strumieniami ?
forEach
nie jest zgodny z porządkiem spotkania (jeśli jest zdefiniowany) i jest z natury niedeterministyczny, gdzie tak jak forEachOrdered
. Więc forEach
nie gwarantuje, że zamówienie zostanie zachowane. Sprawdź również to , aby uzyskać więcej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-29 05:52:35
Java 8:
Możesz używać wyrażeń lambda:
myMap.entrySet().stream().forEach((entry) -> {
Object currentKey = entry.getKey();
Object currentValue = entry.getValue();
});
Aby uzyskać więcej informacji, wykonaj to .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-06 03:37:46
Spróbuj z Javą 1.4:
for( Iterator entries = myMap.entrySet().iterator(); entries.hasNext();){
Entry entry = (Entry) entries.next();
System.out.println(entry.getKey() + "/" + entry.getValue());
//...
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-07 14:34:44
W Mapach można iterację nad keys
i / lub values
i / lub both (e.g., entrySet)
zależy od zainteresowania_ jak:
-
Iterować przez
keys -> keySet()
z mapy:Map<String, Object> map = ...; for (String key : map.keySet()) { //your Business logic... }
-
Iterować przez
values -> values()
z mapy:for (Object value : map.values()) { //your Business logic... }
-
Iterować przez
both -> entrySet()
z mapy:for (Map.Entry<String, Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); //your Business logic... }
Ponadto istnieją 3 różne sposoby iteracji za pomocą Hashmapy. Są one jak poniżej:
//1.
for (Map.Entry entry : hm.entrySet()) {
System.out.print("key,val: ");
System.out.println(entry.getKey() + "," + entry.getValue());
}
//2.
Iterator iter = hm.keySet().iterator();
while(iter.hasNext()) {
Integer key = (Integer)iter.next();
String val = (String)hm.get(key);
System.out.println("key,val: " + key + "," + val);
}
//3.
Iterator it = hm.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Integer key = (Integer)entry.getKey();
String val = (String)entry.getValue();
System.out.println("key,val: " + key + "," + val);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-30 15:21:24
Najbardziej kompaktowy z Java 8:
map.entrySet().forEach(System.out::println);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-19 12:32:20
Jeśli posiadasz mapę generyczną, możesz użyć:
Map map = new HashMap();
for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) {
System.out.println(entry.getKey() + "/" + entry.getValue());
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-16 16:17:58
public class abcd{
public static void main(String[] args)
{
Map<Integer, String> testMap = new HashMap<Integer, String>();
testMap.put(10, "a");
testMap.put(20, "b");
testMap.put(30, "c");
testMap.put(40, "d");
for (Integer key:testMap.keySet()) {
String value=testMap.get(key);
System.out.println(value);
}
}
}
Lub
public class abcd {
public static void main(String[] args)
{
Map<Integer, String> testMap = new HashMap<Integer, String>();
testMap.put(10, "a");
testMap.put(20, "b");
testMap.put(30, "c");
testMap.put(40, "d");
for (Entry<Integer, String> entry : testMap.entrySet()) {
Integer key=entry.getKey();
String value=entry.getValue();
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-07 14:34:13
Jeśli mam obiekt implementujący interfejs mapy w Javie i chcę iterację nad każdą parą w nim zawartą, jaki jest najbardziej efektywny sposób przechodzenia przez mapę?
Jeśli wydajność zapętlania kluczy jest priorytetem dla Twojej aplikacji, wybierz implementację Map
, która utrzymuje klucze w żądanej kolejności.
Tak, oczywiście.Czy kolejność elementów zależy od konkretnej implementacji mapy, którą mam dla interfejs?
- niektóre implementacje
Map
obiecują pewną kolejność iteracji, inne nie. - różne implementacje
Map
zachowują różną kolejność par klucz-wartość.
Zobacz tabelę, którą stworzyłem podsumowując różne implementacje Map
w pakiecie z Java 11. W szczególności zwróć uwagę na kolumnę porządku iteracji . Kliknij / stuknij, aby powiększyć.
Widzisz istnieją cztery implementacje utrzymujące porządek :
TreeMap
-
ConcurrentSkipListMap
LinkedHashMap
EnumMap
NavigableMap
interfejs
Dwa z nich realizują NavigableMap
interfejs: TreeMap
& ConcurrentSkipListMap
.
The older SortedMap
interfejs jest skutecznie wypierany przez nowsze NavigableMap
interfejs. Ale możesz znaleźć implementacje innych firm implementujące tylko starszy interfejs.
Naturalne zamówienie
Jeśli chcesz Map
która utrzymuje swoje pary ułożone według "naturalnego porządku" klucza, użyj TreeMap
lub ConcurrentSkipListMap
. Termin "porządek naturalny" oznacza klasę klawiszy Comparable
. Wartość zwracana przez compareTo
metoda jest używana do porównywania w sortowaniu.
Zamówienie na zamówienie
Jeśli chcesz określić niestandardową procedurę sortowania dla kluczy, które mają być używane do utrzymywania sortowanego porządku, podaj Comparator
implementacja odpowiednia do klasy Twoich kluczy. Użyj albo TreeMap
lub ConcurrentSkipListMap
, mijając swoje Comparator
.
Oryginalna kolejność wstawiania
Jeśli chcesz, aby pary twojej mapy były utrzymywane w pierwotnej kolejności, w jakiej je wstawiłeś do mapy, użyj LinkedHashMap
.
Enum-porządek definicji
Jeśli używasz enum, takiego jak DayOfWeek
lub Month
jako swoje klucze, użyj EnumMap
klasy. Nie tylko ta klasa jest wysoce zoptymalizowana tak, aby zużywała bardzo mało pamięci i działała bardzo szybko, ale utrzymuje pary w kolejności określonej przez enum. Dla DayOfWeek
, na przykład, klucz DayOfWeek.MONDAY
zostanie znaleziony po iteracji, a klucz DayOfWeek.SUNDAY
będzie ostatni.
Inne względy
Wybierając implementację Map
należy również wziąć pod uwagę:
- NULLs. Niektóre implementacje zabraniają / akceptują NULL jako klucz i / lub wartość.
- współbieżność. Jeśli manipulując mapą między wątkami, musisz użyć implementacji obsługującej współbieżność. Lub zawinąć mapę z
Collections::synchronizedMap
(mniej korzystne).
Obie te kwestie zostały omówione w powyższej tabeli graficznej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-13 05:39:06
Kolejność zawsze zależy od konkretnej implementacji mapy. W Javie 8 można użyć jednego z następujących elementów:
map.forEach((k,v) -> { System.out.println(k + ":" + v); });
Lub:
map.entrySet().forEach((e) -> {
System.out.println(e.getKey() + " : " + e.getValue());
});
Wynik będzie taki sam (ta sama kolejność). EntrySet wspierany przez mapę, więc dostajesz tę samą kolejność. Drugi jest przydatny, ponieważ pozwala na używanie lambda, np. jeśli chcesz drukować tylko obiekty całkowite, które są większe niż 5:
map.entrySet()
.stream()
.filter(e-> e.getValue() > 5)
.forEach(System.out::println);
Poniższy kod pokazuje iterację poprzez LinkedHashMap i normalną Hashmapę (przykład). Ty zobaczy różnicę w kolejności:
public class HMIteration {
public static void main(String[] args) {
Map<Object, Object> linkedHashMap = new LinkedHashMap<>();
Map<Object, Object> hashMap = new HashMap<>();
for (int i=10; i>=0; i--) {
linkedHashMap.put(i, i);
hashMap.put(i, i);
}
System.out.println("LinkedHashMap (1): ");
linkedHashMap.forEach((k,v) -> { System.out.print(k + " (#="+k.hashCode() + "):" + v + ", "); });
System.out.println("\nLinkedHashMap (2): ");
linkedHashMap.entrySet().forEach((e) -> {
System.out.print(e.getKey() + " : " + e.getValue() + ", ");
});
System.out.println("\n\nHashMap (1): ");
hashMap.forEach((k,v) -> { System.out.print(k + " (#:"+k.hashCode() + "):" + v + ", "); });
System.out.println("\nHashMap (2): ");
hashMap.entrySet().forEach((e) -> {
System.out.print(e.getKey() + " : " + e.getValue() + ", ");
});
}
}
Wyjście:
LinkedHashMap (1):
10 (#=10):10, 9 (#=9):9, 8 (#=8):8, 7 (#=7):7, 6 (#=6):6, 5 (#=5):5, 4 (#=4):4, 3 (#=3):3, 2 (#=2):2, 1 (#=1):1, 0 (#=0):0,
LinkedHashMap (2):
10 : 10, 9 : 9, 8 : 8, 7 : 7, 6 : 6, 5 : 5, 4 : 4, 3 : 3, 2 : 2, 1 : 1, 0 : 0,
HashMap (1):
0 (#:0):0, 1 (#:1):1, 2 (#:2):2, 3 (#:3):3, 4 (#:4):4, 5 (#:5):5, 6 (#:6):6, 7 (#:7):7, 8 (#:8):8, 9 (#:9):9, 10 (#:10):10,
HashMap (2):
0 : 0, 1 : 1, 2 : 2, 3 : 3, 4 : 4, 5 : 5, 6 : 6, 7 : 7, 8 : 8, 9 : 9, 10 : 10,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-30 17:26:53
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry element = (Map.Entry)it.next();
LOGGER.debug("Key: " + element.getKey());
LOGGER.debug("value: " + element.getValue());
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-14 20:58:30
Możesz to zrobić używając generyków:
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<Integer, Integer> entry = entries.next();
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-16 15:54:24
Użyj Javy 8:
map.entrySet().forEach(entry -> System.out.println(entry.getValue()));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-17 19:03:40
Efektywnym rozwiązaniem iteracyjnym nad mapą jest pętla for
od Javy 5 do Javy 7. Tutaj jest:
for (String key : phnMap.keySet()) {
System.out.println("Key: " + key + " Value: " + phnMap.get(key));
}
W Javie 8 można używać wyrażenia lambda do iteracji na mapie. Jest to wzmocnione forEach
phnMap.forEach((k,v) -> System.out.println("Key: " + k + " Value: " + v));
Jeśli chcesz napisać warunkową dla lambda, możesz napisać ją w następujący sposób:
phnMap.forEach((k,v)->{
System.out.println("Key: " + k + " Value: " + v);
if("abc".equals(k)){
System.out.println("Hello abc");
}
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-30 12:08:36
//Functional Oprations
Map<String, String> mapString = new HashMap<>();
mapString.entrySet().stream().map((entry) -> {
String mapKey = entry.getKey();
return entry;
}).forEach((entry) -> {
String mapValue = entry.getValue();
});
//Intrator
Map<String, String> mapString = new HashMap<>();
for (Iterator<Map.Entry<String, String>> it = mapString.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, String> entry = it.next();
String mapKey = entry.getKey();
String mapValue = entry.getValue();
}
//Simple for loop
Map<String, String> mapString = new HashMap<>();
for (Map.Entry<String, String> entry : mapString.entrySet()) {
String mapKey = entry.getKey();
String mapValue = entry.getValue();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-13 07:47:46
Tak, jak wiele osób zgodziło się, że jest to najlepszy sposób na iterację Map
.
Ale są szanse rzucić nullpointerexception
jeśli mapa jest null
. Nie zapomnij umieścić null
.zgłoś się.
|
|
- - - -
|
|
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-06 22:40:17
Jest na to wiele sposobów. Poniżej kilka prostych kroków:
Załóżmy, że masz jedną mapę typu:
Map<String, Integer> m = new HashMap<String, Integer>();
Następnie możesz zrobić coś takiego jak poniżej, aby iterację elementów mapy.
// ********** Using an iterator ****************
Iterator<Entry<String, Integer>> me = m.entrySet().iterator();
while(me.hasNext()){
Entry<String, Integer> pair = me.next();
System.out.println(pair.getKey() + ":" + pair.getValue());
}
// *********** Using foreach ************************
for(Entry<String, Integer> me : m.entrySet()){
System.out.println(me.getKey() + " : " + me.getValue());
}
// *********** Using keySet *****************************
for(String s : m.keySet()){
System.out.println(s + " : " + m.get(s));
}
// *********** Using keySet and iterator *****************
Iterator<String> me = m.keySet().iterator();
while(me.hasNext()){
String key = me.next();
System.out.println(key + " : " + m.get(key));
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-22 10:10:05