2020. 7. 6. 16:32ㆍSpring/Java
알고리즘을 공부하는 도중...
한 번 정리하고 가야겠다는 생각으로 시작하는 자바 클래스 포스팅
자바, 부셔보자 👊🏻
🗺 MAP ❓
자바에서의 Map 자료형은 '키 key'과 '속성 value'로 이루어져 있습니다.
일상에서의 예시를 들자면, 사전과 비슷한데요.
예를 들어 영한사전에서 'apple'이라는 단어가 있다면, '사과'라는 의미를 갖고 있는 것을 찾을 수 있겠죠?
'apple'과 '사과'는 한 쌍으로 묶여있습니다.
이처럼, Map 자료형도 key와 value가 한 쌍으로 묶여 저장되어있습니다.
마치 배열에서 정수 index를 참조하여 해당 index의 데이터를 참고하는 것과 비교해보면
index를 자신의 입맛에 맞는 타입으로 설정해서 데이터를 참고하는 것으로 보면 좀 더 이해가 쉬울 것 같아요 〰️
Map의 특징
Map의 특징을 몇 개 적어보자면, 아래와 같습니다.
- key는 값을 찾는 인덱스이기 때문에 중복이 불가능 Unique합니다.
- Map 자료형은 순서를 신경쓰지 않는다.
- 파이썬에서는 dictionary라고도 쓰인다.
Map의 종류
JAVA는 다양한 Map 자료형을 지원하는데, HashMap 뿐만 아니라 TreeMap과 LinkedHashMap도 있습니다.
저장방식의 차이인데요.
TreeMap 은 내부적으로 RedBlack Tree로 저장됩니다. 키값에 대한 Compartor 구현으로 정렬 순서를 바꿀수 있죠.
LinkedHashMap은 링크드 리스트로 저장됩니다. 그렇기 때문에 순서가 보장되죠.
마지막으로 HashMap은 아래에서 더욱 더 자세하게 다뤄보도록 하겠습니다.
🏜 HashMap
HashMap은 내부적으로 Entry<K,V>[] Entry 의 array 로 되어 있습니다.
해당 array에 index는 내부 해쉬 함수를 통해 계산됩니다.
// hashmap 생성
Map<String, String> map = new HashMap<>();
// map.put(key, value)의 형식으로 map에 데이터 추가
map.put("Integer", "aa");
map.put("Float", "bb");
map.put("String", "cc");
map.put("Boolean", "dd");
map.put("Map", "aa");
map.put("HashMap", "bb");
map.put("TreeMap", "cc");
map.put("LinkedHashMap", "dd");
// map의 key들만 가져와서 순회 - keySet()은 Set자료형 반환
for (String s : map.keySet()) {
System.out.println(s);
}
위와 같은 코드가 있을 때, 출력은 어떻게 될까요❓
Integer
Float
HashMap
String
Boolean
TreeMap
Map
LinkedHashMap
위와 같이 출력이 됩니다. 저장되었던 순서와는 상관없이 출력되는 것을 확인할 수 있습니다.
이제부터는 Map에서 사용할 수 있는 메소드를 알아보도록 하겠습니다.
.put (key, value)
✔️ 반환값 : void
put 메소드는 위의 예제에서 본 것 처럼 Map 자료형에 데이터를 추가할 수 있습니다.
.get (key)
✔️ 반환값 : Object value
get 메소드는 key값을 참조해서 해당하는 value를 가져옵니다.
.containsKey (key)
✔️ 반환값 : Boolean
containsKey 메소드는 Map 데이터에 key가 존재하는 지 확인하여 존재여부를 반환해줍니다.
예를 들어 위의 예제에서 아래의 코드를 추가한다면, Float라는 key 데이터를 추가하였기 때문에 true라는 boolean 타입의 데이터를 반환해줄 것입니다.
map.containsKey("Float"); // true
map.containsKey("float"); // false
.containsValue (value)
✔️ 반환값 : Boolean
위와 비슷하게 key가 아닌 value가 존재하는지 확인하는 메소드입니다.
위와 비슷한 맥락으로 사용해주시면 됩니다 〰️
.remove (key)
✔️ 반환값 : Object value
remove 메소드는 해당하는 key의 데이터를 삭제합니다.
그리곤 key값에 해당하는 value를 출력해줍니다.
System.out.println(map.remove("Float")); // bb
위의 코드를 보면, "Float"이라는 키값에 해당하는 value인 bb가 출력되는 것을 확인할 수 있습니다.
.size ()
✔️ 반환값 : int
size는 map에 저장된 개수를 출력해줍니다.
System.out.println(map.size()); // 8
위의 예제에서 map.size()를 출력하면 8개가 출력되는 것을 확인할 수 있습니다.
🎡 Using More Efficiently
HashMap을 더욱 효율적으로 사용하기 위해서 'lambda expression' 를 사용해보도록 하겠습니다.
.forEach (element -> {logic})
✔️ 반환값 : void
위의 예제에서는 모든 요소를 출력하기 위해서 for문을 사용했습니다.
이번에는 forEach를 사용해보도록 해볼게요.
key 출력
// 기존 방식
for (String s : map2.keySet()) {
System.out.println(s);
}
// forEach 사용
map.keySet().forEach(key -> System.out.println(key));
위와 같이 사용할 수 있습니다.
위의 예제에서는 key를 출력했는데요, 이 번엔 value를 출력해볼까요?
value 출력
var values = map.values();
values.forEach(value -> System.out.println(value));
// or
map.values().forEach(value -> System.out.println(value));
위와 같이 표현할 수 있습니다.
이번에는 key와 value를 함께 접근해보도록 하겠습니다.
key & value 출력
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.print("key: "+ entry.getKey());
System.out.println(", Value: "+ entry.getValue());
}
// or (lambda expression)
map.forEach((key, value) -> {
System.out.print("key: "+ key);
System.out.println(", Value: "+ value);
});
.computeIfAbsent(key, (key) -> {})
map 데이터에 key값을 가진 쌍이 있는지 확인합니다.
만약 없다면 다음 인자에 있는 함수 로직을 실행합니다.
함수의 return 값을 value로 map에 데이터를 삽입합니다.
피보나치로 예시를 한 번 들어볼까요❓
아래의 예제를 보면 memizeHashMap을 사용합니다.
메모이제이션(memoization)을 사용해서 피보나치를 더 효율적으로 만들어주기 위함이죠.
메모이제이션(memoization)은 중복된 값이 발생할 가능성이 있는 경우, 계산 결과를 미리 저장해두어 필요할 때 사용하는 기술입니다.
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
public class Fibonacci {
private Map<Integer, BigInteger> memoizeHashMap = new HashMap<>();
{
memoizeHashMap.put(0, BigInteger.ZERO);
memoizeHashMap.put(1, BigInteger.ONE);
memoizeHashMap.put(2, BigInteger.ONE);
}
private BigInteger fibonacci(int n) {
if (memoizeHashMap.containsKey(n)) {
return memoizeHashMap.get(n);
} else {
BigInteger result = fibonacci(n - 1).add(fibonacci(n - 2));
memoizeHashMap.put(n, result);
return result;
}
}
public static void main(String[] args) {
Fibonacci fibonacci = new Fibonacci();
for (int i = 0; i < 100; i++) {
System.out.println(fibonacci.fibonacci(i));
}
}
}
위의 코드에서 fibonacci 메소드 확인해보면 n이라는 키의 여부에 따라 분기처리를 해주었습니다.
이 때, computeIfAbsent 메소드를 사용하면 간결하게 사용할 수 있습니다.
private BigInteger fibonacci (int n) {
return memoizeHashMap.computeIfAbsent(n,
(key) -> fibonacci(n - 1).add(fibonacci(n - 2)));
}
위의 코드처럼요❗️
상당히 간단해졌죠?
비슷하게 putIfAbsent(key, ()->{}) 메소드도 있는데요.차이점은 putIfAbsent() 는 key값이 존재해도 다음 인자로 들어온 함수를 실행합니다.
더 자세한 사항은 이 곳을 참조하세요 ❗️
.getOrDefault(key, default value)
key 값을 확인해서 있다면, 해당하는 value를 없다면 두 번째 인자를 반환합니다.
오늘은 HashMap 자료형에 대해 알아보았는데요.
다음에도 더 많은 자료형으로 포스팅해보아야겠어요~.~
'Spring > Java' 카테고리의 다른 글
Masking Name with Regex, in java (0) | 2022.05.29 |
---|---|
Java Date & Time, 제대로 사용하기 (2) | 2022.05.22 |
ENUM, Clean Code with Java (0) | 2022.05.11 |
Matcher, 어렵지 않게 사용하기 (2) | 2020.08.24 |
Pattern, 어렵지 않게 사용하기 (2) | 2020.08.18 |
Backend Software Engineer
𝐒𝐮𝐧 · 𝙂𝙮𝙚𝙤𝙣𝙜𝙨𝙪𝙣 𝙋𝙖𝙧𝙠