HashMap의 키 존재 확인


309

HashMap에 키가 있는지 항상 확인해야합니까?

1000 개의 항목이있는 HashMap이 있고 효율성을 개선하려고합니다. HashMap에 매우 자주 액세스하는 경우 모든 액세스에서 키가 있는지 확인하면 오버 헤드가 커집니다. 대신 키가 존재하지 않아 예외가 발생하면 예외를 잡을 수 있습니다. (이것이 드물게 일어날 것이라는 것을 알 때). 이렇게하면 HashMap에 대한 액세스가 절반으로 줄어 듭니다.

이것은 좋은 프로그래밍 관행은 아니지만 액세스 횟수를 줄이는 데 도움이됩니다. 아니면 여기에 뭔가 빠졌습니까?

[ Update ] HashMap에 null 값이 없습니다.


8
"따라서 예외가 발생합니다"-어떤 예외? 이것은 java.util.HashMap에서 온 것이 아닙니다 ...
serg10

답변:


513

널값을 저장 한 적이 있습니까? 그렇지 않은 경우 다음을 수행 할 수 있습니다.

Foo value = map.get(key);
if (value != null) {
    ...
} else {
    // No such key
}

그렇지 않으면, 당신은 할 수 당신이 반환에 null 값을 얻는 경우에 단지 존재를 확인 :

Foo value = map.get(key);
if (value != null) {
    ...
} else {
    // Key might be present...
    if (map.containsKey(key)) {
       // Okay, there's a key but the value is null
    } else {
       // Definitely no such key
    }
}

1
@Samuel : null이 가능한 값인 경우에만. 지도에 null 값이없는 경우에는 문제가 없으며 값 get이 필요할 때 두 번의 조회를 수행하지 않아도됩니다.
Jon Skeet

예를 들어 이것은 분명하지만 if(value!=null || map.containsKey(key)), 두 번째 부분을 작성할 수도 있습니다 . 적어도 동일한 방법으로 코드를 반복하지 않으려는 경우. 단락 으로 인해 작동 합니다.
Cullub

66

키가 있는지 확인하여 아무것도 얻지 못합니다. 이것은 코드입니다 HashMap:

@Override
public boolean containsKey(Object key) {
    Entry<K, V> m = getEntry(key);
    return m != null;
}

@Override
public V get(Object key) {
    Entry<K, V> m = getEntry(key);
    if (m != null) {
        return m.value;
    }
    return null;
}

의 반환 값이과 get()다른지 확인하십시오 null.

이것은 HashMap 소스 코드입니다.


자료 :


2
이 메소드의 특정 구현을 보여주는 요점은 무엇입니까?
jarnbjo

2
대부분의 경우 키가 존재하는지 확인하면 값을 얻는 것과 거의 같은 시간이 걸립니다. 따라서 값을 얻기 전에 실제로 존재하는 키를 확인하기 위해 아무것도 최적화하지 않습니다. 나는 그것이 일반화라는 것을 알고 있지만 이해하는 데 도움이 될 수 있습니다.
콜린 헤 버트

좋은 링크는 grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…(OpenJDK 는 Sun 코드에서 매우 강력하게 파생 됨)이며 잘못된 것 같습니다. Java5 버전과 Java6을 비교하고있었습니다. 이 영역에서는 다르게 작동하지만 게시 한 스 니펫과 마찬가지로 둘 다 정확합니다.
Donal Fellows

2
인정 된 답변에서 지적했듯이,이 스나이퍼는 명백한 잘못입니다. 물론 값을 비교하는 키 존재를 확인하여 무언가를 얻습니다. 존재하지 않는 키를 존재하지만 키로 값으로 매핑되는 키와 구별 할 수 있습니다.
Johannes H.

43

더 좋은 방법은의 방법을 사용 containsKey하는 것입니다 HashMap. 내일 누군가는지도에 null을 추가 할 것입니다. 키 유무와 키에 null 값이 있는지 구분해야합니다.


네. 또는 HashMap을 서브 클래 싱하여 모두 저장하지 못하게 null합니다.
RobAu

1
이 답변을 사용하여 불필요한 유형의 캐스트가 필요하지 않은 기본 유형의 경우 1+
Prashant Bhanarkar

null을 확인하는 것보다 .containsKey ()를 작성하는 것이 더 유창합니다. 우리는 읽기 쉬운 것에 대해 더 걱정할 필요가 있으며, 이는 대부분의 경우 약간의 최적화보다 개발자 시간을 절약 해줍니다. 필요하기 전에 최소한 최적화하지 마십시오.
최대

23

당신은 같은 코드를 가지고 있다는 것을 의미합니까?

if(map.containsKey(key)) doSomethingWith(map.get(key))

여기 저기 ? 그런 다음 map.get(key)null을 반환 했는지 확인해야 합니다. 그런데 HashMap은 누락 된 키에 대한 예외를 throw하지 않고 대신 null을 반환합니다. containsKey널값과 결 측값을 구별하기 위해 널값을 저장하는 경우가 유일한 경우 이지만, 이는 일반적으로 나쁜 습관으로 간주됩니다.


8

containsKey()명확성을 위해 사용하십시오 . 빠르고 코드를 깨끗하고 읽을 수있게 유지합니다. 의 전체 지점 HashMap의 키 조회가 빠른 것을 단지 확인을 할 것입니다 hashCode()equals()제대로 구현됩니다.


4
if(map.get(key) != null || (map.get(key) == null && map.containsKey(key)))

3

에서 computeIfAbsent()방법을 사용할 수도 있습니다HashMap클래스 .

다음 예에서는 map키에 적용되는 트랜잭션 (정수) 목록 (은행 계좌 이름)을 저장합니다. 2 개 거래 추가 100200checking_account당신이 쓸 수 있습니다 :

HashMap<String, ArrayList<Integer>> map = new HashMap<>();
map.computeIfAbsent("checking_account", key -> new ArrayList<>())
   .add(100)
   .add(200);

이 방법으로 키의 checking_account존재 여부를 확인할 필요 가 없습니다.

  • 존재하지 않으면 람다 식에 의해 생성되고 반환됩니다.
  • 존재하는 경우 키 값이로 반환됩니다 computeIfAbsent().

정말 우아합니다! 👍


0

나는 보통 관용구를 사용한다

Object value = map.get(key);
if (value == null) {
    value = createValue(key);
    map.put(key, value);
}

즉, 키가 없으면지도를 두 번만 누르십시오.


0
  1. 키 클래스를 사용하는 경우 hashCode () 및 equals () 메소드가 구현되었는지 확인하십시오.
  2. 기본적으로 HashMap에 대한 액세스는 O (1)이어야하지만 잘못된 hashCode 메소드 구현에서는 동일한 해시 키가있는 값이 링크 된 목록으로 저장되므로 O (n)이됩니다.

0

Jon Skeet의 답변 은 두 가지 시나리오 ( null가치가 아닌 null가치가있는 맵 )를 효율적으로 처리합니다.

숫자 입력 및 효율성 문제에 대해 무언가를 추가하고 싶습니다.

1.000 개의 항목이있는 HashMap이 있고 효율성을 개선하려고합니다. HashMap에 매우 자주 액세스하는 경우 모든 액세스에서 키가 있는지 확인하면 오버 헤드가 커집니다.

항목이 1.000 인지도는 큰지도가 아닙니다.
5.000 또는 10.000 개의 항목이있는지도
Map이러한 치수로 빠른 검색을 수행하도록 설계되었습니다.

이제는 hashCode()맵 키의 분포가 양호 하다고 가정합니다 .

Integer키 유형으로 사용할 수있는 경우 수행하십시오. 고유 한 값에 대해서는 충돌이 불가능하기
때문에이 hashCode()방법은 매우 효율적입니다 int.

public final class Integer extends Number implements Comparable<Integer> {
    ...
    @Override
    public int hashCode() {
        return Integer.hashCode(value);
    }

    public static int hashCode(int value) {
        return value;
    }
    ...
}

키의 경우 다른 내장과 같은 유형 사용할 필요가 String종종 사용된다 예를 들어 Map, 당신은 몇 가지 충돌이있을 수 있지만에서 개체의 일부 수천 1000에서 Map는 AS 그것의 거의를, 당신이해야 String.hashCode()하는 방법 좋은 분포를 제공합니다.

사용자 정의 유형을 사용하는 경우 재정의 hashCode()하고 equals()올바르게 재정의 하고 전체적으로 hashCode()공정한 분포 를 제공하십시오.
9의 항목을 Java Effective참조하십시오. 방법을 자세히 설명
하는 게시물 이 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.