• 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

+ Recent posts