Home [Java][Collections] Map 인터페이스
Post
Cancel
Preview Image

[Java][Collections] Map 인터페이스

All Known Subinterfaces


가장 먼저 어떤 인터페이스를 보기 시작할까를 고민하다가,

그래도 나에게 가장 익숙한 Map 부터 보기로 했다.

정의

Map 인터페이스의 가장 처음 정의를 보면 다음과 같다.

1
2
3
4
public interface Map<K, V>

An object that maps keys to values.
A map cannot contain duplicate keys; each key can map to at most one value.

오!

수학에서의 Map 정의와 비슷하다.

Key 값과 Value 값을 매핑한 것이며,

  1. Map은 중복된 키 값을 가질 수 없으며,
  2. 각 키들은 최대 하나의 값을 가질 수 있다.

여기서 “각 키들은 최대 하나의 값을 가질 수 있다.” 라는 부분이 수학에서의 함수와 다르다.

수학에서는 각 키들은 오직 하나의 값에만 매핑되어야 한다.

하지만, 자바의 Map에서는 키 또는 값이 null일 수 있기 때문에,

최대 하나의 값을 가질 수 있다고 한다.

Map 인터페이스는 3가지의 컬렉션으로도 볼 수 있다.

  1. 키들의 Set
  2. 값들의 Collection
  3. 키-값 매핑들의 집합

Map의 order은 Map의 Collection views에 있는 iterator가 요소를 반환하는 순서로 정의된다.

TreeMap과 같은 Map 구현체는 이런 정렬을 보장하지만, HashMap과 같은 클래스는 그렇지 않다.

이 경우에는 mutable object를 Map 키로 하는 경우에는 매우 주의해야 한다.

특별한 케이스는 Map 그 자체가 키로써 포함하는 것이 허용되지 않는다는 것이다.

Map이 자신을 값으로 포함하는 것을 허용하지만, equals 및 hashCode에서는 더이상 이러한 Map에서 잘 정의되지 않는다는 점을 매우 유의하자.

이 설명은 매우 간단하게 이해할 수 있다.

Map은 키를 통해 값을 가져오는 구조체이다.

값에 대한 다른 키들은 존재할 수 있지만, 동등한 키에 대해서는 동등한 값이 나와야 한다.

만약 그것을 보장하지 않는다면… 정의에 어긋나서 더 이상 사용하는 의미가 없다.

생성자

모든 일반적인 목적의 Map 구현의 객체들은 반드시 2개의 기본 생성자를 제공해야한다.

  1. a void (no arguments) constructor which creates an empty Map
    • 비어있는 Map을 생성할 수 있는 생성자
  2. a constructor with a single argument of type Map, which creates a new map with the same key-value mappings as its argument
    • 인수와 키 값 매핑이 동일한 새 map을 만드는 map 유형의 단일 인수가 있는 생성자

첫번째 생성자는 쉽게 이해가 간다. 두번째 생성자는 Map을 인수로 받아서, 그 Map의 키-값 매핑을 그대로 가지는 생성자라는 의미이다.

사실 두 번째 생성자는 사용자들에게 어떤 Map이든 복사해서 원하는 클래스에 동일한 Map을 생산하기 위해서 제공된다.

하지만 이러한 추천을 강제하는 방식은 없다.

당장 인터페이스만 봐도, 해당하는 생성자를 포함시켜 놓지 않았다.

하지만 대부분 구현해놓았다.

파괴적인 메서드들

동작하는 Map을 수정하는 파괴적인 메서드들은, 그 Map이 해당 작업을 지원하지 않으면 UnsupportedOperationException을 던지도록 되어있다.

예를 들어 수정불가한 Map에 대해서 putAll method를 실행했을 때,

mapping들이 중복되어야할 Map이 비어있는 경우 예외를 던진다.

키, 값들에 대한 제한

몇몇 Map 구현체들은 그들이 관리하는 키들과 값들에 대해서 제한을 가지기도 한다.

예를 들어, 몇몇 구현들은 null 키들과 값들을 제한하기도 하고,

NullPointerException 이나 ClassCastException 같은 unchecked exception을 던진다.

부적합한 키 또는 값의 존재를 쿼리하려고 하면 예외가 발생하거나 단순히 거짓으로 반환될 수 있다.

일부 구현에서는 이전 동작을 보여주고 일부는 후자를 표시한다.

보다 일반적으로, 완성되지 않은 키 또는 값에 대한 연산을 시도하여 Map에 부적격 요소를 삽입하지 않을 경우, 구현 옵션에서 예외를 발생시키거나 성공할 수 있다.

이러한 예외는 이 인터페이스의 사양에 “optional”으로 표시된다.

equals

Collections 프레임워크 인터페이스들의 많은 메서드들은 equals라는 메서드를 정의하고 있다.

예를 들어 containsKey(Object key) 메서드는,

“returns true if and only if this map contains a mapping for a key k such that (key==null ? k==null : key.equals(k)).”

라고 말한다.

보다 일반적으로, 다양한 컬렉션 프레임워크 인터페이스의 구현은 구현자가 적절하다고 생각하는 모든 곳에서 Object methods의 지정된 동작을 자유롭게 이용할 수 있다.

재귀적 호출

Map의 재귀적 통과를 수행하는 일부 Map 작업은 Map이 직접 또는 간접적으로 자신을 포함하는 자기 참조 인스턴스에 대한 예외로 실패할 수 있다.

이는 clone(), equals(), hashCode(), toString() 메서드들을 포함한다.

구현들은 선택적으로 자기 참조 시나리오를 처리할 수 있지만, 대부분의 현재 구현은 그렇게 하지 않는다.

Unmodifiable Maps

Map.of, Map.ofEntries, Map.copyOf정적 팩터리 메서드들은 unmodifiable maps을 생성하는 편리한 방법을 제공한다.

이러한 메서드들을 가지는 Map은 다음과 같은 특징들을 가지고 있다.

  • 그들은 수정할 수 없다.
    • 키와 값들이 더해지거나, 제거되거나, 수정될 수 없다.
    • 이 맵에 수정하는 메서드를 실행하게 되면, UnsupportedOperationException을 던지게 된다.
    • 그러나, 포함되어있는 키와 값들 자신은 수정할 수 있다면, 이것은 그 Map의 가변성과 값들이 변할 수 있음을 야기할 수 있다.
  • 그들은 null 키 또는 값들을 허용하지 않는다.
    • 만약 그렇게 시도한다면, NullPointerException을 던지게 된다.
  • 그들은 모든 키와 값들이 serializable 하면, serializable 하다.
  • 그들은 생성 시에 중복된 키를 거부한다.
    • 만약 중복된 키가 있다면, 정적 팩터리 메서드가 IllegalArgumentException를 던진다.
  • 매핑들의 반복 순서는 지정되지 않았으며 변경될 수 있다.
  • 그들은 값 중심적이다.
    • Caller들은 반환된 인스턴스들의 존재성에 대한 가정을 할 필요가 없다.
    • Factory들은 새로운 인스턴스를 만들거나, 이미 존재하는 것을 재사용하는 것에 자유롭다.
    • 그러므로, 그 인스턴스들에 대한 존재성에 민감한 연산들은 신뢰할 수 없으니 피해야 한다.

References

This post is licensed under CC BY 4.0 by the author.

zsh 로딩 빠르게 하는 방법

[Java][Collections] Bindings 인터페이스와 SimpleBindings 클래스