1. 설명
Java의 Map 탐색 방법과 관련하여 많은 기사에서는 keySet보다 훨씬 효율적이라고 간주되는 EntrySet 사용을 권장합니다. 그 이유는 다음과 같습니다. EntrySet 메소드는 모든 키와 값 세트를 한 번에 가져오는 반면, keySet은 각 키에 대해 해당 값을 한 번 더 검색해야 하므로 키 수가 줄어듭니다. 전반적인 효율성. 그렇다면 실제 상황은 어떠한가?
키+값 순회, 키 순회, 값 순회 등과 같은 다양한 시나리오의 차이를 포함하여 순회 성능의 실제 차이를 이해하기 위해 몇 가지 비교 테스트를 수행하려고 했습니다.
2. 비교 테스트
처음에는 간단한 테스트만 진행했는데 결과적으로 keySet의 성능이 더 좋다고 해서 다들 의아해했습니다. 추가 검증을 위해 보다 자세한 비교 테스트를 위해 다양한 테스트 데이터가 사용되었습니다.
2.1 테스트 데이터
2.1.1 HashMap 테스트 데이터
HashMap-1, 크기는 1백만이고, 키와 값은 모두 문자열이며, 키 값은 1, 2, 3...1000000입니다.
다음과 같이 코드 코드를 복사합니다.
Map<String, String> map = new HashMap<String, String>();
문자열 키, 값;
for (i = 1; i <= num; i++) {
키 = "" + i;
값 = "값";
map.put(키, 값);
}
HashMap-2, 크기는 100만, 키와 값은 모두 문자열, 키 값은 50, 100, 150, 200,..., 50000000입니다.
다음과 같이 코드 코드를 복사합니다.
Map<String, String> map = new HashMap<String, String>();
문자열 키, 값;
for (i = 1; i <= num; i++) {
키 = "" + (i * 50);
값 = "값";
map.put(키, 값);
}
2.1.2 TreeMap 테스트 데이터
TreeMap-1, 크기는 1백만이고, 키와 값은 모두 문자열이며, 키 값은 1, 2, 3...1000000입니다.
다음과 같이 코드 코드를 복사합니다.
Map<String, String> map = new TreeMap<String, String>();
문자열 키, 값;
for (i = 1; i <= num; i++) {
키 = "" + i;
값 = "값";
map.put(키, 값);
}
TreeMap-2, 크기는 100만, 키와 값은 모두 문자열이며, 키 값은 50, 100, 150, 200,..., 50000000, 더 이산적입니다.
다음과 같이 코드 코드를 복사합니다.
Map<String, String> map = new TreeMap<String, String>();
문자열 키, 값;
for (i = 1; i <= num; i++) {
키 = "" + (i * 50);
값 = "값";
map.put(키, 값);
}
2.2 테스트 시나리오
keySet, EntrySet, Values의 다양한 쓰기 방법을 사용하여 키+값 순회, 키 순회, 값 순회라는 세 가지 시나리오를 테스트합니다.
2.2.1 트래버스 키+값
keySet은 키+값을 순회합니다(작성 방법 1):
다음과 같이 코드 코드를 복사합니다.
Iterator<String> iter = map.keySet().iterator();
동안(iter.hasNext()) {
키 = iter.next();
값 = map.get(키);
}
keySet은 키+값을 순회합니다(작성 방법 2):
다음과 같이 코드 코드를 복사합니다.
for (문자열 키 : map.keySet()) {
값 = map.get(키);
}
EntrySet는 키+값을 순회합니다(쓰기 방법 1):
다음과 같이 코드 코드를 복사합니다.
Iterator<Entry<String, String>> iter = map.entrySet().iterator();
Entry<문자열, 문자열> 항목;
동안(iter.hasNext()) {
항목 = iter.next();
키 = Entry.getKey();
값 = 항목.getValue();
}
EntrySet는 키+값을 순회합니다(작성 방법 2):
다음과 같이 코드 코드를 복사합니다.
for (Entry<String, String> 항목: map.entrySet()) {
키 = Entry.getKey();
값 = 항목.getValue();
}
2.2.2 트래버스 키
keySet은 키를 탐색합니다(쓰기 방법 1):
다음과 같이 코드 코드를 복사합니다.
Iterator<String> iter = map.keySet().iterator();
동안(iter.hasNext()) {
키 = iter.next();
}
keySet은 키를 탐색합니다(작성 방법 2):
다음과 같이 코드 코드를 복사합니다.
for (문자열 키 : map.keySet()) {
}
EntrySet가 키를 트래버스합니다(쓰기 방법 1):
다음과 같이 코드 코드를 복사합니다.
Iterator<Entry<String, String>> iter = map.entrySet().iterator();
동안(iter.hasNext()) {
키 = iter.next().getKey();
}
EntrySet가 키를 트래버스합니다(작성 방법 2):
다음과 같이 코드 코드를 복사합니다.
for (Entry<String, String> 항목: map.entrySet()) {
키 = Entry.getKey();
}
2.2.3 트래버스 값
keySet은 값을 탐색합니다(쓰기 방법 1):
다음과 같이 코드 코드를 복사합니다.
Iterator<String> iter = map.keySet().iterator();
동안(iter.hasNext()) {
값 = map.get(iter.next());
}
keySet은 값을 탐색합니다(작성 방법 2):
다음과 같이 코드 코드를 복사합니다.
for (문자열 키 : map.keySet()) {
값 = map.get(키);
}
EntrySet는 값을 트래버스합니다(쓰기 방법 1):
다음과 같이 코드 코드를 복사합니다.
Iterator<Entry<String, String>> iter = map.entrySet().iterator();
동안(iter.hasNext()) {
값 = iter.next().getValue();
}
EntrySet는 값을 트래버스합니다(작성 방법 2):
다음과 같이 코드 코드를 복사합니다.
for (Entry<String, String> 항목: map.entrySet()) {
값 = 항목.getValue();
}
값이 값을 순회합니다(작성 방법 1):
다음과 같이 코드 코드를 복사합니다.
Iterator<String> iter = map.values().iterator();
동안(iter.hasNext()) {
값 = iter.next();
}
값은 값을 순회합니다(작성 방법 2):
다음과 같이 코드 코드를 복사합니다.
for (문자열 값 : map.values()) {
}
2.3 테스트 결과
2.3.1 HashMap 테스트 결과
단위: 밀리초 | 해시맵-1 | 해시맵-2 |
| keySet은 키+값을 순회합니다(쓰기 방법 1) | 39 | 93 |
| keySet은 키+값을 순회합니다(작성 방법 2) | 38 | 87 |
| EntrySet는 키+값을 순회합니다(쓰기 방법 1). | 43 | 86 |
| EntrySet는 키+값을 순회합니다(작성 방법 2). | 43 | 85 |
단위: 밀리초 | 해시맵-1 | 해시맵-2 |
| keySet은 키를 순회합니다(작성 방법 1) | 27 | 65 |
| keySet은 키를 순회합니다(작성 방법 2) | 26 | 64 |
| EntrySet가 키를 트래버스합니다(작성 방법 1) | 35 | 75 |
| EntrySet가 키를 트래버스함(작성 방법 2) | 34 | 74 |
단위: 밀리초 | 해시맵-1 | 해시맵-2 |
| keySet은 값을 순회합니다(작성 방법 1) | 38 | 87 |
| keySet이 값을 순회함(작성 방법 2) | 37 | 87 |
| EntrySet가 값을 트래버스함(작성 방법 1) | 34 | 61 |
| EntrySet가 값을 트래버스함(작성 방법 2) | 32 | 62 |
| 값 트래버스 값 (작성 방법 1) | 26 | 48 |
| 값을 가로지르는 값(쓰기 방법 2) | 26 | 48 |
2.3.2 TreeMap 테스트 결과
단위: 밀리초 | 트리맵-1 | 트리맵-2 |
| keySet은 키+값을 순회합니다(쓰기 방법 1) | 430 | 451 |
| keySet은 키+값을 순회합니다(작성 방법 2) | 429 | 450 |
| EntrySet는 키+값을 순회합니다(쓰기 방법 1). | 77 | 84 |
| EntrySet는 키+값을 순회합니다(작성 방법 2). | 70 | 68 |
단위: 밀리초 | 트리맵-1 | 트리맵-2 |
| keySet은 키를 순회합니다(작성 방법 1) | 50 | 49 |
| keySet은 키를 순회합니다(작성 방법 2) | 49 | 48 |
| EntrySet가 키를 트래버스합니다(작성 방법 1) | 66 | 64 |
| EntrySet가 키를 트래버스함(작성 방법 2) | 65 | 63 |
단위: 밀리초 | 트리맵-1 | 트리맵-2 |
| keySet은 값을 순회합니다(작성 방법 1) | 432 | 448 |
| keySet이 값을 순회함(작성 방법 2) | 430 | 448 |
| EntrySet가 값을 트래버스함(작성 방법 1) | 62 | 61 |
| EntrySet가 값을 트래버스함(작성 방법 2) | 62 | 61 |
| 값 트래버스 값 (작성 방법 1) | 46 | 46 |
| 값을 가로지르는 값(작성방법 2) | 45 | 46 |
3. 결론
3.1 HashMap을 사용하는 경우
1. 키와 값을 동시에 순회할 때 keySet과 EntrySet 메소드의 성능 차이는 복잡성(복잡한 객체), 불연속성, 충돌률 등과 같은 키의 특정 조건에 따라 달라집니다. 즉, HashMap에서 가치를 찾는 비용에 따라 달라집니다. 모든 키와 값을 한 번에 검색하는 EntrySet의 작업은 성능 오버헤드가 있습니다. 이 손실이 값을 찾는 HashMap의 오버헤드보다 작을 경우에는 EntrySet의 성능 이점이 반영됩니다. 예를 들어, 위의 비교 테스트에서 키가 가장 간단한 숫자 문자열인 경우 keySet은 EntrySet보다 시간이 10% 더 적게 소요되어 더 효율적일 수 있습니다. 일반적으로 EntrySet을 사용하는 것이 좋습니다. 키가 매우 단순할 경우 성능은 keySet보다 약간 낮을 수 있지만 키가 복잡해지면 제어가 가능하므로 EntrySet의 장점이 명확하게 반영됩니다. 물론 실제 상황에 따라 선택할 수 있습니다.
2. 키만 순회하는 경우에는 keySet 메소드가 더 적합합니다. 왜냐하면 EntrySet은 성능과 공간을 낭비하는 쓸모없는 값도 가져오기 때문입니다. 위의 테스트 결과에서 keySet은entrySet 메소드보다 23% 더 적은 시간이 소요됩니다.
3. 값만 순회하는 경우 vlaues 방법을 사용하는 것이 최선의 선택이며, keySet 방법보다 EntrySet이 약간 더 좋습니다.
4. 다양한 순회 쓰기 방법 중에서 약간 더 효율적인 다음 쓰기 방법을 사용하는 것이 좋습니다.
다음과 같이 코드 코드를 복사합니다.
for (문자열 키 : map.keySet()) {
값 = map.get(키);
}
for (Entry<String, String> 항목: map.entrySet()) {
키 = Entry.getKey();
값 = 항목.getValue();
}
for (문자열 값 : map.values()) {
}
3.2 TreeMap을 사용하는 경우
1. 키와 값을 동시에 순회할 경우 HashMap과 달리 EntrySet의 성능이 keySet의 성능보다 훨씬 높습니다. 이는 TreeMap의 쿼리 효율성에 따라 결정됩니다. 즉, TreeMap에서 값을 검색하는 비용은 상대적으로 크며, 이는 EntrySet에서 모든 키와 값을 한 번에 검색하는 비용보다 훨씬 높습니다. 따라서 TreeMap을 순회할 때 EntrySet 메소드를 사용하는 것이 좋습니다.
2. 키만 순회하는 경우에는 keySet 메소드가 더 적합합니다. 왜냐하면 EntrySet은 성능과 공간을 낭비하는 쓸모없는 값도 가져오기 때문입니다. 위의 테스트 결과에서 keySet은 EntrySet 메소드보다 24% 더 적은 시간이 소요됩니다.
3. 값만 순회할 때는 vlaues 메소드를 사용하는 것이 최선의 선택이며, keySet 메소드보다 EntrySet도 확실히 더 좋습니다.
4. 다양한 순회 쓰기 방법 중에서 약간 더 효율적인 다음 쓰기 방법을 사용하는 것이 좋습니다.
다음과 같이 코드 코드를 복사합니다.
for (문자열 키 : map.keySet()) {
값 = map.get(키);
}
for (Entry<String, String> 항목: map.entrySet()) {
키 = Entry.getKey();
값 = 항목.getValue();
}
for (문자열 값 : map.values()) {
}