Java Map의 각 항목을 효율적으로 반복하려면 어떻게해야합니까?


3302

MapJava로 인터페이스를 구현하는 객체가 있고 그 안에 포함 된 모든 쌍을 반복하려면 맵을 통과하는 가장 효율적인 방법은 무엇입니까?

요소의 순서는 인터페이스에 대한 특정 맵 구현에 따라 달라 집니까?


38
Lambda Expression을 사용하는 Java 8 : stackoverflow.com/a/25616206/1503859
Nitin Mahesh

답변:


5029
Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}

93
그렇게하면 Entry가 Map의 중첩 클래스이므로 작동하지 않습니다. java.sun.com/javase/6/docs/api/java/util/Map.html
ScArcher2

266
"import java.util.Map.Entry;"로 가져 오기를 작성할 수 있습니다. 작동합니다.
jjujuma

55
@Pureferret 반복자를 사용하려는 유일한 이유는 해당 remove메소드 를 호출해야하기 때문 입니다. 그런 경우, 이 다른 응답 쇼 당신은 그것을 수행하는 방법에 대해 설명합니다. 그렇지 않으면 위의 답변에 표시된 향상된 루프가 진행됩니다.
assylias

102
내부 클래스를 현재 네임 스페이스로 가져 오는 것보다 Map.Entry 형식이 더 명확하다고 생각합니다.
JosiahYoder-deactive 다음을 제외하고.

31
값이나 키만 반복 map.values()하거나 사용할 수 있습니다 map.keySet().
dguay

1215

다른 답변을 요약하고 내가 아는 것과 결합하기 위해 10 가지 주요 방법을 찾았습니다 (아래 참조). 또한 성능 테스트를 작성했습니다 (아래 결과 참조). 예를 들어,지도의 모든 키와 값의 합계를 찾으려면 다음과 같이 쓸 수 있습니다.

  1. 사용 반복자의 Map.Entry를

    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();
    }
  2. 사용 의 foreach의 Map.Entry를

    long i = 0;
    for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
        i += pair.getKey() + pair.getValue();
    }
  3. Java 8에서 forEach 사용

    final long[] i = {0};
    map.forEach((k, v) -> i[0] += k + v);
  4. 사용 keySet 반환foreach 문을

    long i = 0;
    for (Integer key : map.keySet()) {
        i += key + map.get(key);
    }
  5. 사용 keySet 반환반복자를

    long i = 0;
    Iterator<Integer> itr2 = map.keySet().iterator();
    while (itr2.hasNext()) {
        Integer key = itr2.next();
        i += key + map.get(key);
    }
  6. 사용 을 위해의 Map.Entry

    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();
    }
  7. Java 8 스트림 API 사용

    final long[] i = {0};
    map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
  8. Java 8 Stream API 병렬 사용

    final long[] i = {0};
    map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());
  9. 사용 IterableMap 의를Apache Collections

    long i = 0;
    MapIterator<Integer, Integer> it = iterableMap.mapIterator();
    while (it.hasNext()) {
        i += it.next() + it.getValue();
    }
  10. 이클립스 (CS) 컬렉션의 MutableMap 사용

    final long[] i = {0};
    mutableMap.forEachKeyValue((key, value) -> {
        i[0] += key + value;
    });

성능 테스트 (모드 = AverageTime, 시스템 = Windows 8.1 64 비트, Intel i7-4790 3.60GHz, 16GB)

  1. 작은지도 (100 개 요소)의 경우 점수 0.308이 최고입니다

    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
  2. 요소가 10000 개인지도의 경우 37.606 점이 최고입니다.

    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
  3. 100000 개의 요소가있는지도의 경우 1184.767 점이 최고입니다

    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

그래프 (지도 크기에 따른 성능 테스트)

여기에 이미지 설명을 입력하십시오

표 (지도 크기에 따른 성능 테스트)

          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

모든 테스트는 GitHub에서 이루어 집니다.


9
@ Viacheslav : 아주 좋은 답변입니다. 그냥 예를 들어 (... 람다를 캡처하여 Java8의 API를, 벤치 마크에 방해되는 방법 궁금 long sum = 0; map.forEach( /* accumulate in variable sum*/);포착 sum한, 말보다 속도가 느려질 수있다 stream.mapToInt(/*whatever*/).sum물론 당신은 항상 상태를 캡처 피할 수없는 중. 예를 들어,하지만 그건 reasonnable 추가 될 수있다 벤치에
GPI

17
8 번의 시험이 잘못되었습니다. 동기화하지 않고 다른 스레드에서 동일한 변수에 액세스합니다. AtomicInteger문제 해결을 위해로 변경하십시오 .
talex

44
@ ZhekaKozlov : 엄청나게 큰 오류 값을보십시오. 의 테스트 결과는 ~ x±e사이의 간격 내에 결과가 있었음 을 의미 하므로 가장 빠른 결과 ( )는 ~ 사이 이며 가장 느린 두 번째 ( )는 ~ 사이에 있으며 결과는 여전히 겹칩니다. 이제, 가장 느린 결과를 보면 , 사이 발산하는 것을 의미하는 그리고 당신은 알고 이러한 테스트 결과는 의미가있다. x-ex+e1184.767±332.96885215181706.676±436.867127021443289.866±1445.56418444735
Holger

8
HashMap, LinkedHashMap 및 TreeMap의 세 가지 주요 구현을 비교하는 것은 어떻습니까?
Thierry

9
# 1과 # 6은 정확히 같습니다. 루프를 사용 while하는 for것은 반복하는 다른 기술이 아닙니다. 그리고 테스트에서 테스트 사이에 이러한 차이가 있다는 사실에 놀랐습니다. 이는 테스트하려는 대상과 관련이없는 외부 요소와 테스트가 제대로 분리되지 않았 음을 나타냅니다.
ErikE

294

Java 8에서는 새로운 람다 기능을 사용하여 깨끗하고 빠르게 할 수 있습니다.

 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));

의 유형 kv컴파일러에 의해 추정되며 사용할 필요가 없다 Map.Entry더 이상은.

쉬워요!


12
맵으로 수행하려는 작업에 따라 map.entrySet().stream() docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html에서
Vitalii Fedorenko

1
forEach () 내에서 람다 식 외부에서 선언 된 비 최종 변수를 참조하려는 경우에는 작동하지 않습니다.
Chris

7
@ 크리스탈. 람다 외부에서 비 최종 변수를 효과적으로 사용하려고하면 작동하지 않습니다 .
코디네이터

243

예, 순서는 특정지도 구현에 따라 다릅니다.

@ ScArcher2는보다 우아한 Java 1.5 구문을 가지고 있습니다. 1.4에서는 다음과 같은 작업을 수행합니다.

Iterator entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Entry thisEntry = (Entry) entries.next();
  Object key = thisEntry.getKey();
  Object value = thisEntry.getValue();
  // ...
}

41
for-loop를 while보다 선호하십시오. for (Iterator entries = myMap.entrySet (). iterator (); entries.hasNext ();) {...}이 구문을 사용하면 '엔트리'범위가 for 루프 만 .
jai

8
@jpredham 당신은 사용 권리한다는 것이다 for으로 구조를 for (Entry e : myMap.entrySet)당신이 컬렉션을 수정할 수 없지만, @HanuAthena 같은 예는 당신에게 제공하기 때문에 그것이 작동합니다 언급 한 Iterator범위. (내가 뭔가 빠진 것이 아니라면 ...)
pkaeding

1
IntelliJ에서 오류가 발생했습니다 Entry thisEntry = (Entry) entries.next();: 인식하지 못합니다 Entry. 그 의사 코드가 다른 것입니까?
JohnK

1
@JohnK를 가져 오십시오 java.util.Map.Entry.
pkaeding

1
정수 키와 문자열 키가 있으면이 솔루션이 작동하지 않습니다.

140

지도를 반복하는 일반적인 코드는 다음과 같습니다.

Map<String,Thing> map = ...;
for (Map.Entry<String,Thing> entry : map.entrySet()) {
    String key = entry.getKey();
    Thing thing = entry.getValue();
    ...
}

HashMap표준 맵 구현이며 보장하지 않습니다 (또는 돌연변이 작업이 수행되지 않으면 순서를 변경해서는 안됩니다). SortedMap키의 자연 순서에 따라 항목을 반환하거나 Comparator제공된 경우을 반환합니다 . LinkedHashMap구성 방식에 따라 게재 신청서 또는 액세스 순서로 항목을 반환합니다. EnumMap자연 순서대로 키를 반환합니다.

(업데이트 :. 나는 이것이 더 이상 진실이라고 생각하지 않습니다 ) 참고 IdentityHashMap entrySet반복자는 현재 같은 반환하는 특유의 구현이 Map.Entry의 모든 항목에 대한 인스턴스를 entrySet! 그러나 새로운 반복자가 진행할 때마다 Map.Entry가 업데이트됩니다.


6
EnumMap은 또한 IdentityHashMap
Premraj

1
"LinkedHashMap은 [...] 액세스 순서 [...]"의 항목을 반환하므로 액세스 한 순서대로 요소에 액세스합니까? 긴장을 유발할 수있는 긴장된 것, 또는 흥미로운 것. ;-)
jpaugh

5
@jpaugh LinkedHashMap카운트 에만 직접 액세스합니다 . 그 통해가 iterator, spliterator, entrySet, 등의 순서를 수정하지 않습니다.
Tom Hawtin-tackline

1
1. 그래도만약 ? 2. 마지막 단락은 브러시 업에서 도움이 될 수 있습니다.
피터 Mortensen

121

반복자와 제네릭을 사용하는 예 :

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();
  // ...
}

14
Iterator범위를 제한하려면 for 루프를 넣어야 합니다.
Steve Kuo

@SteveKuo "범위 제한"은 무엇을 의미합니까?
StudioWorks

12
@StudioWorks for (Iterator<Map.Entry<K, V>> entries = myMap.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<K, V> entry = entries.next(); }. 해당 구문을 사용하여 (변수의 가시성) 범위를 entriesfor 루프로 제한합니다.
ComFreek

3
@ComFreek 아, 알겠습니다. 그것이 그렇게 중요하다는 것을 몰랐습니다.
StudioWorks

102

이것은 두 가지 질문입니다.

@ ScArcher2 맵의 항목을 반복하는 방법 은 완벽하게 답변 했습니다.

반복 순서는 무엇인가 -만약 당신이 단지 사용 Map하고 엄격히 말하면, 순서 보장없다 . 따라서 구현에서 제공 한 순서에 의존해서는 안됩니다. 그러나 SortedMap인터페이스가 확장 Map되어 원하는 것을 정확하게 제공합니다. 구현은 일관된 정렬 순서를 제공합니다.

NavigableMap또 다른 유용한 확장입니다 -이것은 SortedMap키 세트에서 순서대로 위치를 찾는 추가 방법입니다. 그래서 가능성이 처음부터 반복의 필요성을 제거 할 수 있습니다 - 당신은 특정 찾을 수 있습니다 entry당신이 사용 후입니다 higherEntry, lowerEntry, ceilingEntry, 또는 floorEntry방법. 이 descendingMap방법 은 순회 순서취소 하는 명시적인 방법도 제공합니다 .


84

지도를 반복하는 방법에는 여러 가지가 있습니다.

다음은 맵에 백만 개의 키 값 쌍을 저장하여 맵에 저장된 공통 데이터 세트의 성능을 비교 한 것이며 맵을 반복합니다.

1) entrySet()각 루프에 사용

for (Map.Entry<String,Integer> entry : testMap.entrySet()) {
    entry.getKey();
    entry.getValue();
}

50 밀리 초

2) keySet()각 루프에 사용

for (String key : testMap.keySet()) {
    testMap.get(key);
}

76 밀리 초

3) 사용 entrySet()및 반복자

Iterator<Map.Entry<String,Integer>> itr1 = testMap.entrySet().iterator();
while(itr1.hasNext()) {
    Map.Entry<String,Integer> entry = itr1.next();
    entry.getKey();
    entry.getValue();
}

50 밀리 초

4) 사용 keySet()및 반복자

Iterator itr2 = testMap.keySet().iterator();
while(itr2.hasNext()) {
    String key = itr2.next();
    testMap.get(key);
}

75 밀리 초

나는 언급했다 this link.


1
런타임은 Java Microbenchmarking Harness를 사용하지 않는 기사에서 가져옵니다. 예를 들어, 코드가 JIT 컴파일러에 의해 완전히 최적화 되었기 때문에 시간은 신뢰할 수 없습니다.
AlexB

59

이를 수행하는 올바른 방법은 승인 된 답변을 가장 효율적으로 사용하는 것입니다. 다음 코드가 약간 깨끗해 보입니다.

for (String key: map.keySet()) {
   System.out.println(key + "/" + map.get(key));
}

15
이것은 최선의 방법은 아니며 entrySet ()을 사용하는 것이 훨씬 효율적입니다. Findbugs 깃발이 코드를 (볼 findbugs.sourceforge.net/...를 )
제프 올슨

6
@JeffOlson meh, 실제로는 아닙니다. 맵 조회는 O (1)이므로 두 루프가 동일한 방식으로 동작합니다. 분명히, 그것은 마이크로 벤치 마크에서 약간 느려 지지만 때로는 반복해서 유형 인수를 쓰는 것을 싫어하기 때문에이 작업을 수행합니다. 또한 이것은 성능 병목 현상이 될 수 없으므로 코드를 더 읽기 쉽게 만들면 좋습니다.
kritzikratzi

4
더 자세하게 설명 O(1) = 2*O(1)하면 큰 O 표기법의 정의와 거의 같습니다 . 조금 느리게 실행되지만 복잡성 측면에서 동일하다는 점에서 맞습니다.
kritzikratzi

2
충돌 여부에 관계없이 몇 번의 충돌이 발생하더라도 문제가되지 않는다는 것을 의미합니다. 충돌이있는 경우 분명히 다른 이야기입니다. 그래서 당신은 꽤 사소하지만 당신이 말하는 것은 사실입니다.
kritzikratzi

2
@ 제프 올슨 (Jeff Olson) : 상수 요인 만있을 때 "Big O"복잡성이 변하지 않는다는 의견은 정확합니다. 그래도, 한 시간 또는 두 시간이 걸리는 작업이 중요합니다. 더 중요한 것은,이 요소 를 반복하는 것이 조회를 전혀하지 않기 때문에이 요소가 아니라는 점을 강조해야합니다 . 그것은 모든 항목의 선형 순회입니다. 반면에,를 통해 반복 키 곰 당 조회를 수행 우리가 제로 대 조회에 대해 얘기하고, 그래서 키 당 조회를 N 여기 조회, N 의 크기 인 . 따라서 요인은 …2entrySet()keySet()Map2
Holger

57

참고로, 당신은 또한 사용할 수 있습니다 map.keySet()그리고 map.values()당신은 단지 다른 맵의 키 / 값에 관심하지 않는 경우.


42

함께 자바 8 , 당신은지도 foreach는 람다 표현식을 사용하여 반복 할 수 있습니다,

map.forEach((k, v) -> System.out.println((k + ":" + v)));

41

함께 이클립스 컬렉션 , 당신은 사용하는 것이 forEachKeyValue온 방법 MapIterable에 의해 상속 인터페이스 MutableMapImmutableMap인터페이스와 그 구현.

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);

익명의 내부 클래스를 사용하여 다음과 같이 코드를 작성할 수 있습니다.

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);

참고 : 저는 Eclipse Collections의 커미터입니다.


37

람다 식 자바 8

Java 1.8 (Java 8)에서는 Iterable Interface의 반복자와 유사한 집계 작업 ( Stream operations )의 forEach 메소드를 사용하여 훨씬 쉬워졌습니다 .

아래 명령문을 코드에 복사하고 HashMap 변수의 이름 을 hm 에서 HashMap 변수로 바꾸어 키-값 쌍을 인쇄하십시오.

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.

다음은 Lambda Expression을 사용하여 시도한 샘플 코드입니다 . 이 물건은 너무 멋지다. 꼭 해봐.

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

또한 Spliterator 를 사용할 수 있습니다 .

Spliterator sit = hm.entrySet().spliterator();

최신 정보


Oracle Docs에 대한 설명서 링크 포함 Lambda 에 대한 자세한 내용은 이 링크 로 이동하여 집계 작업을 읽어야 하며 Spliterator의 경우이 링크 로 이동 하십시오 .


36

이론적으로 가장 효율적인 방법은 Map의 구현에 따라 다릅니다. 이 작업을 수행하는 공식적인 방법은을 호출 map.entrySet()하는 것으로 Map.Entry, 각 집합 에는 키와 값 ( entry.getKey()entry.getValue()) 이 포함되어 있습니다 .

특유의 구현에서는 사용 여부에 따라 약간의 차이가있을 수 있습니다 map.keySet().map.entrySet() 또는 뭔가. 그러나 나는 누군가가 그것을 그렇게 쓰는 이유를 생각할 수 없습니다. 대부분의 경우 성능에 아무런 영향을 미치지 않습니다.

그리고 예, 순서는 구현 순서와 삽입 순서 및 기타 제어하기 어려운 요소에 따라 다릅니다.

[편집] 나는 valueSet()원래 글을 썼지 만 entrySet()실제로는 대답입니다.


36

자바 8

우리는 람다 식forEach 을 받아들이 는 메소드를 얻었다 . 우리는 또한 가지고 스트림 API를. 지도를 고려하십시오.

Map<String,String> sample = new HashMap<>();
sample.put("A","Apple");
sample.put("B", "Ball");

키 반복 :

sample.keySet().forEach((k) -> System.out.println(k));

값을 반복하십시오.

sample.values().forEach((v) -> System.out.println(v));

항목 반복 (forEach 및 Stream 사용) :

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);
        });

스트림의 장점은 원하는 경우 쉽게 병렬화 할 수 있다는 것입니다. 우리는 단순히 위 parallelStream()대신 사용해야 stream()합니다.

forEachOrderedforEach스트림 대 ? forEach만남 순서를 따르지 않으며 (정의 된 경우) 본질적으로 비결정론 적 forEachOrdered입니다. 따라서 forEach주문이 유지된다는 보장은 없습니다. 이것도 더 확인하십시오 .


33

자바 8 :

람다 식을 사용할 수 있습니다.

myMap.entrySet().stream().forEach((entry) -> {
    Object currentKey = entry.getKey();
    Object currentValue = entry.getValue();
});

자세한 내용은 다음을 수행 하십시오 .


@injecteer : 람다 표현의 동기를 보인다
humblerookie

9
지도를 반복하고 싶다면 스트림이 필요하지 않습니다. myMap.forEach( (currentKey,currentValue) -> /* action */ );훨씬 간결합니다.
Holger

29

Java 1.4로 이것을 시도하십시오 :

for( Iterator entries = myMap.entrySet().iterator(); entries.hasNext();){

  Entry entry = (Entry) entries.next();

  System.out.println(entry.getKey() + "/" + entry.getValue());

  //...
}

26

지도에서 한 수 반복 이상 keys및 / 또는 values및 / 또는 both (e.g., entrySet) 하나의 관심처럼 IN_에 따라 달라집니다

  1. keys -> keySet()지도를 반복합니다 .

    Map<String, Object> map = ...;
    
    for (String key : map.keySet()) {
        //your Business logic...
    }
  2. values -> values()지도를 반복합니다 .

    for (Object value : map.values()) {
        //your Business logic...
    }
  3. both -> entrySet()지도를 반복합니다 .

    for (Map.Entry<String, Object> entry : map.entrySet()) {
        String key = entry.getKey();
        Object value = entry.getValue();
        //your Business logic...
    }

_ 또한 HashMap을 반복하는 세 가지 방법이 있습니다. 그들은 아래에 있습니다 __

//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);
}

24

Java 8에서 가장 컴팩트 함 :

map.entrySet().forEach(System.out::println);

21

일반 비 유형지도가있는 경우 다음을 사용할 수 있습니다.

Map map = new HashMap();
for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}

20
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);
        }
    }
}

또는

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();
        }
    }
}

17

Java로 Map 인터페이스를 구현하는 객체가 있고 그 안에 포함 된 모든 쌍을 반복하려면 맵을 통과하는 가장 효율적인 방법은 무엇입니까?

키 루프 효율이 앱의 우선 순위 인 경우 Map원하는 순서대로 키를 유지 하는 구현 을 선택하십시오 .

요소의 순서는 인터페이스에 대한 특정 맵 구현에 따라 달라 집니까?

네 그럼요.

  • 일부 Map구현은 특정 반복 순서를 약속하지만 다른 구현은 그렇지 않습니다.
  • Map키-값 쌍의 다른 순서 를 유지하는 다른 구현 .

MapJava 11과 함께 번들로 제공되는 다양한 구현을 요약 한이 표를 참조하십시오 . 특히 반복 순서 열을 확인하십시오. 클릭 / 탭하여 확대합니다.

기능을 비교 한 Java 11의 맵 구현 표

순서를 유지하는 네 가지 Map구현 이 있음을 알 수 있습니다 .

  • TreeMap
  • ConcurrentSkipListMap
  • LinkedHashMap
  • EnumMap

NavigableMap 상호 작용

그 중 두 가지가 NavigableMap인터페이스를 구현합니다 . TreeMap& ConcurrentSkipListMap.

이전 SortedMap인터페이스는 새로운 NavigableMap인터페이스에 의해 효과적으로 대체됩니다 . 그러나 이전 인터페이스 만 구현하는 타사 구현을 찾을 수 있습니다.

자연 질서

Map키의 "자연 순서"에 따라 쌍을 정렬 하는 을 원하면 TreeMap또는을 사용하십시오 ConcurrentSkipListMap. "자연 질서"라는 용어는 키가 구현하는 클래스를 의미합니다 Comparable. 에 의해 반환되는 값compareTo메소드가 은 정렬에서 비교하는 데 사용됩니다.

맞춤 주문

정렬 순서를 유지하는 데 키가 사용되도록 사용자 정의 정렬 루틴을 지정하려면 Comparator키 클래스에 적합한 구현을 전달 하십시오. TreeMap또는을 사용하여을 ConcurrentSkipListMap전달하십시오 Comparator.

원본 게재 신청서

지도 쌍을지도에 삽입 한 원래 순서대로 유지하려면을 사용하십시오 LinkedHashMap.

열거 정의 순서

당신 같은 열거를 사용하는 경우 DayOfWeek또는 Month사용자의 키와 같이 사용하는 EnumMap클래스를. 뿐만 아니라이 클래스 높게 는 열거에 의해 정의 된 순서대로 쌍을 유지하고, 아주 작은 메모리를 사용하도록 최적화 매우 빠르게 실행합니다. 예 DayOfWeek를 들어,의 키는 DayOfWeek.MONDAY반복 될 때 처음 발견되고의 키는 DayOfWeek.SUNDAY마지막입니다.

다른 고려 사항

Map구현을 선택할 때 다음 사항도 고려하십시오.

  • NULL입니다. 일부 구현에서는 NULL을 키 및 / 또는 값으로 금지 / 수락합니다.
  • 동시성. 여러 스레드에서 맵을 조작하는 경우 동시성을 지원하는 구현을 사용해야합니다. 또는지도를 Collections::synchronizedMap(바람직하지 않은)로 감싸십시오 .

이러한 고려 사항은 위의 그래픽 표에서 다룹니다.


파티에 늦었 던 답변에 대한 늦은 의견 (그러나 매우 유익한). 을 언급 한 것은 +1입니다 EnumMap. 처음 들었 기 때문입니다. 아마도 이것이 유용한 경우가 많이있을 것입니다.
user991710

15

순서는 항상 특정지도 구현에 따라 다릅니다. Java 8을 사용하면 다음 중 하나를 사용할 수 있습니다.

map.forEach((k,v) -> { System.out.println(k + ":" + v); });

또는:

map.entrySet().forEach((e) -> {
            System.out.println(e.getKey() + " : " + e.getValue());
        });

결과는 동일합니다 (동일한 순서). 같은 순서를 얻을 수 있도록 map이 지원하는 entrySet입니다. 두 번째는 람다를 사용할 수 있기 때문에 편리합니다. 예를 들어 5보다 큰 Integer 객체 만 인쇄하려는 경우 :

map.entrySet()
    .stream()
    .filter(e-> e.getValue() > 5)
    .forEach(System.out::println);

아래 코드는 LinkedHashMap 및 일반 HashMap (예)을 통한 반복을 보여줍니다. 순서에 차이가 있습니다.

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() + ", ");
        });
    }
}

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,

해시 맵 (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,

해시 맵 (2) :

0 : 0, 1 : 1, 2 : 2, 3 : 3, 4 : 4, 5 : 5, 6 : 6, 7 : 7, 8 : 8, 9 : 9, 10:10,


14
    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());    
    }

14

Java 8을 사용하십시오.

map.entrySet().forEach(entry -> System.out.println(entry.getValue()));

13

제네릭을 사용하여 수행 할 수 있습니다.

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());
}

12

Map에 대한 효과적인 반복 솔루션은 Java 5에서 Java 7까지 'for each'루프입니다.

for (String key : phnMap.keySet()) {
    System.out.println("Key: " + key + " Value: " + phnMap.get(key));
}

Java 8부터는 람다 식을 사용하여 맵을 반복 할 수 있습니다. 향상된 'forEach'입니다

phnMap.forEach((k,v) -> System.out.println("Key: " + k + " Value: " + v));

람다에 대한 조건부를 작성하려면 다음과 같이 작성할 수 있습니다.

phnMap.forEach((k,v)->{
    System.out.println("Key: " + k + " Value: " + v);
    if("abc".equals(k)){
        System.out.println("Hello abc");
    }
});

10
           //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();

            }

10

이를 수행하는 많은 방법이 있습니다. 다음은 몇 가지 간단한 단계입니다.

다음과 같은 하나의 맵이 있다고 가정하십시오.

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

그런 다음지도 요소를 반복하기 위해 아래와 같은 작업을 수행 할 수 있습니다.

// ********** 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));
}

9
package com.test;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class Test {

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("ram", "ayodhya");
        map.put("krishan", "mathura");
        map.put("shiv", "kailash");

        System.out.println("********* Keys *********");
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(key);
        }

        System.out.println("********* Values *********");
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println(value);
        }

        System.out.println("***** Keys and Values (Using for each loop) *****");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        }

        System.out.println("***** Keys and Values (Using while loop) *****");
        Iterator<Entry<String, String>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry<String, String>) entries
                    .next();
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        }

        System.out
                .println("** Keys and Values (Using java 8 using lambdas )***");
        map.forEach((k, v) -> System.out
                .println("Key: " + k + "\t value: " + v));
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.