Map
Key, Value 형태로 데이터를 저장하는 자료구조
HashMap
선언
일반적으로 변수 부분은 인터페이스로 선언하는게 확장에 유리하다.
Map<String, String> map = new HashMap<>();데이터 삽입
V put(K key, V value) 로 값을 넣을 수 있다.
put(k, v) 을 했을 때 이미 키값이 존재한다면 데이터를 덮어쓴다.
putIfAbsent 을 이용하면 Map 에 Key 값이 없을 때에만 데이터를 넣을 수 있다.
map.put("animal", "cat"); // {animal=cat}
map.put("food", "pizza"); // {animal=cat, food=pizza}
// 이미 "animal" 키값이 있기 때문에 "dog" 로 갱신되지 않음
map.putIfAbsent("animal", "dog"); // {animal=cat, food=pizza}
map.putIfAbsent("animal2", "dog"); // {animal=cat, animal2=dog, food=pizza}데이터 가져오기
V get(Object key) 로 value 값을 가져올 수 있다.
V getOrDefault(Object key, V defaultValue) 을 사용하면 key 값이 없을 때 null 대신 설정된 값을 리턴한다.
map.get("animal"); // "cat"
map.getOrDefault("food", "chicken"); // "pizza"
map.getOrDefault("food2", "chicken"); // "chicken"데이터 삭제
V remove(Object key) 로 데이터를 삭제 할 수 있다.
map.remove("animal2");데이터 확인
boolean containsKey(Object key) 또는 boolean containsValue(Object value) 로 key 나 value 값이 존재하는 지 확인할 수 있다.
map.containsKey("food"); // true
map.containsValue("dog"); // false크기(길이) 확인
map.size();Key, Value 묶음 가져오기
Set<K> keySet() 은 Key들로 이루어진 Set 자료구조를 리턴한다.
Collection<V> values() 은 Value 들로 이루어진 Collection 을 리턴한다.
// map: {animal=cat, food=pizza}
map.keySet(); // [animal, food]
map.values(); // [cat, pizza]Map 순회
forEach 를 사용해서 Map 을 순회할 수 있다.
람다식을 이용하면 좀더 간단하게 나타낼 수 있으며 코드가 한줄이라면 중괄호 { } 를 생략할 수 있다.
// 출력
// animal: cat
// food: pizza
map.forEach((k, v) -> {
System.out.println(k + ": " + v);
});
// 한 줄이면 중괄호 { } 생략 가능
map.forEach((k, v) -> System.out.println(k + ": " + v));
// 람다식 안쓰고 for 문으로 구현. forEach 도 내부적으로는 이렇게 구현되어있음
for (Map.Entry entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}Compute
compute 를 사용해 원하는 로직을 실행하고 데이터를 넣을 수 있다.
만약 Key 가 없으면 새로운 데이터를 넣어주고 Key 값이 있으면 데이터를 갱신해준다.
만약 기존에 없는 데이터로 compute 연산을 하게 될 때 value 값은 null 이 된다.
map.compute("animal", (k, v) -> {
System.out.println(k + "'s value is " + v + " -> lion"); // animal's value is cat -> lion
return "lion";
});
// map: {animal=lion, food=pizza}computeIfAbsent 와 computeIfPresent 는 조건을 걸어서 compute 연산을 실행한다.
computeIfAbsent 는 Key 가 없을 때만 실행되기 때문에 람다식으로도 key 값 하나 밖에 받지 않는다.
computeIfPresent 는 Key 값이 존재할 때만 실행된다.
만약 Key 가 없거나 있어서 조건이 일치하지 않으면 로직이 아예 실행되지 않는다.
map.computeIfAbsent("fruit", (k) -> {
System.out.println("New value of " + k + " is apple"); // New value of fruit is apple
return "apple";
});
// map: {fruit=apple, animal=lion, food=pizza}
map.computeIfPresent("animal", (k, v) -> {
System.out.println(k + "'s value is " + v + " -> tiger"); // animal's value is lion -> tiger
return "tiger";
});
// map: {fruit=apple, animal=tiger, food=pizza}LinkedHashMap
HashMap 은 hashcode 를 사용하기 때문에 순서가 일정하지 않다.
LinkedHashMap 은 내부를 Double-Linked List 로 구성하여 HashMap 의 순서를 유지한다.
HashMap 에서 상속받기 때문에 HashMap 의 모든 메소드를 사용할 수 있다.
순서 유지
데이터는 먼저 들어간 데이터가 무조건 앞에 위치하게 된다.
forEach 문에서도 동일하다.
Map<String, String> map = new LinkedHashMap<>();
map.put("animal", "cat");
map.put("fruit", "apple");
System.out.println(map); // {animal=cat, fruit=apple}
map.put("animal", "dog");
System.out.println(map); // {animal=dog, fruit=apple}
map.forEach((k, v) -> System.out.print(k + ": " + v + ", ")); // animal: dog, fruit: apple, 접근 빈도에 따른 순서 변경
LinkedHashMap 은 생성자 파라미터로 accessOrder 라는 값을 받는다.
accessOrder 는 기본값이 false 인데, 만약 true 로 설정한다면 LinkedHashMap 의 접근 빈도에 따라서 순서가 바뀌게 된다.
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}아래 코드는 위와 완전히 동일하지만 accessOrder 만 true 로 생성한 LinkedHashMap 이다.
"animal" 키를 먼저 넣었지만 중간에 put 메소드로 "animal" 키에 접근을 했기 때문에 순서가 바뀌었다.
put 뿐만 아니라 get 이나 compute 에도 동일하게 동작한다 (containsKey 는 바뀌지 않음)
Map<String, String> map = new LinkedHashMap<>(16, 0.75f, true);
map.put("animal", "cat");
map.put("fruit", "apple");
System.out.println(map); // {animal=cat, fruit=apple}
map.put("animal", "dog");
System.out.println(map); // {fruit=apple, animal=dog}
map.forEach((k, v) -> System.out.print(k + ": " + v + ", ")); // fruit: apple, animal: dog,
accessOrder 를 이용하면 가장 첫번째에 존재하는, 즉 가장 사용되지 않은 Entry 를 알 수 있다.
Map.Entry leastUsedEntry = map.entrySet().iterator().next();
int leastUsedKey = map.keySet().iterator().next();
int leastUsedValue = map.values().iterator().next();
// 아래처럼 구할 수도 있다.
leastUsedKey = leastUsedEntry.getKey();
leastUsedValue = leastUsedEntry.getValue();'Language > Java' 카테고리의 다른 글
| Java Stream count() 의 비밀 (0) | 2021.04.18 |
|---|---|
| Java 8 함수형 인터페이스 (Functional Interface) (1) | 2021.04.10 |
| Mac OS Java (OpenJDK) 설치 및 버전 변경 (2) | 2021.03.08 |
| Java Stream 성능비교: Reduce() vs mapToInt().sum() (0) | 2021.02.24 |
| [Java] Static (0) | 2020.09.19 |