- Map : Key, Value 형태로 데이터를 저장하는 자료구조
- HashMap : Map 인터페이스를 구현한 Map 컬렉션 (순서보장X)
- LinkedHashMap : Map 인터페이스를 구현한 Map 컬렉션 (순서보장O)
Map 선언
Map<String, Object> map = new HashMap<String, Object>();
Map value의 자료형이 Object이기 때문에 모든 Object가 다 들어갈 수 있다.
Map<> map = new HashMap<>() 를 사용하는 이유 :
HashMap을 선언 시, Map<String, Object> map = new HashMap<String, Object>(); 과 같은 형식으로 선언한 것을 쉽게 찾아볼 수 있다.
1. 인터페이스니까
▶ 포폴 개발을 진행할 때, List list = new List();와 같이 선언할 수 없었다.
그 이유는 List는 Interface라서 바디를 직접 작성할 수 없기 때문이었다.
Map도 같은 이유이다.
① Map은 인터페이스다.
② 따라서 Body를 직접 작성할 수 없다.
③ HashMap은 Map 인터페이스를 구현했다.
2. 코드의 유연성을 높일 수 있으니까
▶ Map을 구현한 객체는 HashMap, TreeMap 등이 있다.
Map으로 선언할 경우, HashMap으로 선언할 때보다 가짓수가 많아진다.
결국 코드의 유연성을 높일 수 있게 되는 것이다.
① Map map = new TreeMap<>();
② Map map = new HashMap<>();
Map 데이터 삽입
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} Map<String, String> cities = new HashMap<>(); cities.put("Tokyo", "Japan"); cities.put("Seoul", "Korea"); cities.put("Beijing", "China"); cities.put("Paris", "France"); cities.put("Washington", "USA"); cities.put("Brazilia", "Brazil");
V put(K key, V value) 로 값을 넣을 수 있다.
put(k, v) 을 했을 때 이미 키값이 존재한다면 데이터를 덮어쓴다.
putIfAbsent 을 이용하면 Map 에 Key 값이 없을 때에만 데이터를 넣을 수 있다.
Map 데이터 출력
map.get("animal"); // "cat" map.getOrDefault("food", "chicken"); // "pizza" map.getOrDefault("food2", "chicken"); // "chicken" // Normal ways //1) for (Map.Entry<String, String> entry : cities.entrySet()) { System.out.println("Cities: " + entry.getKey() + ", " + entry.getValue()); } //2) for (String key : cities.keySet()) { System.out.println("Cities: " + key + ", " + cities.get(key)); } // Java8 forEach, Lambda // 1) cities.forEach((k, v) -> System.out.println("Cities: " + k + ", " + v)); // 2) cities.forEach((k, v) -> { System.out.println("Cities: " + k + ", " + v); }); //출력결과 Cities: Beijing, China Cities: Tokyo, Japan Cities: Seoul, Korea Cities: Brazilia, Brazil Cities: Paris, France Cities: Washington, USA
V get(Object key) 로 value 값을 가져올 수 있다.
V getOrDefault(Object key, V defaultValue) 을 사용하면 key 값이 없을 때 null 대신 설정된 값을 리턴한다.
Map 데이터 삭제
map.remove("animal2");
V remove(Object key) 로 데이터를 삭제 할 수 있다.
Map 데이터 확인
map.containsKey("food"); // true map.containsValue("dog"); // false
boolean containsKey(Object key) 또는 boolean containsValue(Object value) 로 key 나 value 값이 존재하는 지 확인할 수 있다.
Map 크기(길이) 확인
map.size();
Key, Value 묶음 가져오기
// map: {animal=cat, food=pizza} map.keySet(); // [animal, food] map.values(); // [cat, pizza]
Set<K> keySet() 은 Key들로 이루어진 Set 자료구조를 리턴한다.
Collection<V> values() 은 Value 들로 이루어진 Collection 을 리턴한다.
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()); }
forEach 를 사용해서 Map 을 순회할 수 있다.
람다식을 이용하면 좀더 간단하게 나타낼 수 있으며 코드가 한줄이라면 중괄호 { } 를 생략할 수 있다.
Map Compute 데이터 치환
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} 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}
compute 를 사용해 원하는 로직을 실행하고 데이터를 넣을 수 있다.
만약 Key 가 없으면 새로운 데이터를 넣어주고 Key 값이 있으면 데이터를 갱신해준다.
만약 기존에 없는 데이터로 compute 연산을 하게 될 때 value 값은 null 이 된다.
computeIfAbsent 와 computeIfPresent 는 조건을 걸어서 compute 연산을 실행한다.
computeIfAbsent 는 Key 가 없을 때만 실행되기 때문에 람다식으로도 key 값 하나 밖에 받지 않는다.
computeIfPresent 는 Key 값이 존재할 때만 실행된다.
만약 Key 가 없거나 있어서 조건이 일치하지 않으면 로직이 아예 실행되지 않는다.
LinkedHashMap 순서 유지
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,
HashMap 은 hashcode 를 사용하기 때문에 순서가 일정하지 않다.
LinkedHashMap 은 내부를 Double-Linked List 로 구성하여 HashMap 의 순서를 유지한다.
HashMap 에서 상속받기 때문에 HashMap 의 모든 메소드를 사용할 수 있다.
데이터는 먼저 들어간 데이터가 무조건 앞에 위치하게 된다.
forEach 문에서도 동일하다.
추가 소스package exam; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; public class exam3 { public static void main(String[] args) { Map<String, String> map = new LinkedHashMap<String, String>(); map.put("key01", "value01"); map.put("key02", "value02"); map.put("key03", "value03"); map.put("key04", "value04"); map.put("key05", "value05"); //entrySet() 메서드는 key와 value의 값 모두 출력 //keySet() 메서드는 key의 값만 출력 //Iterator는 자바의 컬렉션 프레임워크에서 컬렉션에 저장되어 있는 요소들을 읽어오는 방법 // 방법 01 : entrySet() for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println("방법1: [key]:" + entry.getKey() + ", [value]:" + entry.getValue()); } System.out.println("----------------------------------------------------------------------------------"); // 방법 02 : keySet() for (String key : map.keySet()) { String value = map.get(key); System.out.println("방법2: [key]:" + key + ", [value]:" + value); } System.out.println("----------------------------------------------------------------------------------"); // 방법 03 : entrySet().iterator() Iterator<Map.Entry<String, String>> iteratorE = map.entrySet().iterator(); while (iteratorE.hasNext()) { Map.Entry<String, String> entry = (Map.Entry<String, String>) iteratorE.next(); String key = entry.getKey(); String value = entry.getValue(); System.out.println("방법3: [key]:" + key + ", [value]:" + value); } System.out.println("----------------------------------------------------------------------------------"); // 방법 04 : keySet().iterator() Iterator<String> iteratorK = map.keySet().iterator(); while (iteratorK.hasNext()) { String key = iteratorK.next(); String value = map.get(key); System.out.println("방법4: [key]:" + key + ", [value]:" + value); } System.out.println("----------------------------------------------------------------------------------"); // 방법 05 : Lambda 사용 map.entrySet().stream().forEach(entry-> { System.out.println("방법5: [key]:" + entry.getKey() + ", [value]:"+entry.getValue()); }); System.out.println("----------------------------------------------------------------------------------"); // 방법 06 : Stream 사용 map.entrySet().stream().forEach(entry-> { System.out.println("방법6-1: [key]:" + entry.getKey() + ", [value]:"+entry.getValue()); }); System.out.println("----------------------------------------------------------------------------------"); // Stream 사용 - 내림차순 map.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry-> { System.out.println("방법6-2: [key]:" + entry.getKey() + ", [value]:"+entry.getValue()); }); System.out.println("----------------------------------------------------------------------------------"); // Stream 사용 - 오름차순 map.entrySet().stream().sorted(Map.Entry.comparingByKey(Comparator.reverseOrder())).forEach(entry-> { System.out.println("방법6-3: [key]:" + entry.getKey() + ", [value]:"+entry.getValue()); }); } }
'JAVA' 카테고리의 다른 글
spring boot 프로젝트 전 개념정리 (0) | 2022.08.29 |
---|---|
List<Map> (0) | 2022.08.04 |
request.getParameter("") (0) | 2022.06.02 |
null과 ""를 구분해서 쓰자.. (0) | 2022.05.18 |
로그인 알고리즘 (0) | 2022.05.18 |