Java Collection Framework: List, Map, Set ํƒ๊ตฌ

Spring Boot๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๋“  ๋Œ€๊ทœ๋ชจ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋“  ๊ฐ„์— List, Map, Set๊ณผ ๊ฐ™์€ ์ž๋ฐ” ์ปฌ๋ ‰์…˜์€ ๊ฑฐ์˜ ๋ชจ๋“  ๋ถ€๋ถ„์—์„œ ์‚ฌ์šฉ๋œ๋‹ค๊ณ  ํ•ด๋„ ๊ณผ์–ธ์ด ์•„๋‹ˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ž๋ฐ” Collection์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

Java Collection Framework(์ดํ•˜ JCF)๋Š” JDK 1.2๋ถ€ํ„ฐ ๋„์ž…๋˜์–ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋ฃน์œผ๋กœ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด ํ‘œ์ค€ํ™”๋œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ์ด์œ ๋Š” ๋ฐ”๋กœ ์ด ๋•Œ๋ฌธ์ด๋‹ค.
JCF๋Š” ํฌ๊ฒŒ ๋‘๊ฐœ์˜ ๋ฟŒ๋ฆฌ๋กœ ๋‚˜๋ˆˆ๋‹ค. ํ•˜๋‚˜๋Š” ๊ฐ์ฒด์˜ ๊ทธ๋ฃน์„ ๋‹ค๋ฃจ๋Š” java.util.Collection ์ธํ„ฐํŽ˜์ด์Šค์ด๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ํ‚ค(Key)์™€ ๊ฐ’(Value)๋ฅผ ๋‹ค๋ฃจ๋Š” java.util.Map ์ธํ„ฐํŽ˜์ด์Šค๋‹ค. Map์€ ์—„๋ฐ€ํžˆ ๋งํ•ด Collection์„ ์ƒ์†๋ฐ›์ง€ ์•Š์ง€๋งŒ JCF์˜ ์ค‘์š”ํ•œ ํ•œ ์ถ•์„ ๋‹ด๋‹นํ•œ๋‹ค.

๋ชฉ์ฐจ

Collection ์ธํ„ฐํŽ˜์ด์Šค

Collection ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋ชจ๋“  ์ปฌ๋ ‰์…˜์ด ๊ฐ–์ถ”์–ด์•ผ ํ•  ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๋™์ž‘์„ ์ •์˜ํ•œ๋‹ค. ์ด๋ฅผ ์ƒ์†๋ฐ›๋Š” ์ฃผ์š” ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • List(๋ฆฌ์ŠคํŠธ): ์ˆœ์„œ๊ฐ€ ์žˆ๋Š” ๋ฐ์ดํ„ฐ์˜ ์ง‘ํ•ฉ์ด๋‹ค. ๋ฐ์ดํ„ฐ์˜ ์ค‘๋ณต์„ ํ—ˆ์šฉํ•˜๋ฉฐ, ์ธ๋ฑ์Šค(Index)๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด ์‹œํ€€์Šค๋ผ๊ณ ๋„ ๋ถˆ๋ฆฐ๋‹ค. ๋Œ€ํ‘œ์ ์ธ ๊ตฌํ˜„์ฒด๋กœ ArrayList, LinkedList, Vector(๋ ˆ๊ฑฐ์‹œ)๊ฐ€ ์žˆ๋‹ค.
  • Set(์…‹): ์ˆ˜ํ•™์˜ ๊ฐœ๋…์„ ๋ชจ๋ธ๋งํ–ˆ๋‹ค. ๋ฐ์ดํ„ฐ์˜ ์ค‘๋ณต์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด๋‚˜ ๊ตฌํ˜„์ฒด์— ๋”ฐ๋ผ ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•˜๊ธฐ๋„ ํ•œ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ HashSet, TreeSet์ด ์žˆ๋‹ค.
  • Queue(ํ): ์ฒ˜๋ฆฌ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์š”์†Œ๋ฅผ ๋ณด๊ด€ํ•˜๋Š” ์šฉ๋„๋กœ ์„ค๊ณ„๋˜์—ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ FIFO(First-In-First-Out) ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€์ง€๋งŒ, ์šฐ์„ ์ˆœ์œ„ ํ(PriorityQueue)์ฒ˜๋Ÿผ ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์ˆœ์„œ๊ฐ€ ๊ฒฐ์ •๋˜๊ธฐ๋„ ํ•œ๋‹ค.
  • Deque(๋ฑ): ‘Double Ended Queue’์˜ ์•ฝ์ž๋กœ ์–‘์ชฝ ๋์—์„œ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋‹ค. Queue๋ฅผ ์ƒ์†๋ฐ›์•˜์ง€๋งŒ Queue์™€๋Š” ์“ฐ์ž„์ƒˆ๊ฐ€ ๊ฝค ๋‹ฌ๋ผ์„œ ๋ณ„๋„์˜ ๋ฟŒ๋ฆฌ๋กœ ์ดํ•ดํ•˜๋ฉด ์ข‹๋‹ค. ์Šคํƒ(Stack)๊ณผ ํ(Queue)์˜ ๊ธฐ๋Šฅ์„ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด ํ™œ์šฉ๋„๊ฐ€ ๋†’๋‹ค.
์ธํ„ฐํŽ˜์ด์Šค์—ญํ•  ๋ฐ ํŠน์ง•์ˆœ์„œ(Order)์ค‘๋ณต
List์ˆœ์„œ๊ฐ€ ์žˆ๋Š” ์ €์žฅ์†Œ(๋ฐฐ์—ด๊ณผ ์œ ์‚ฌ)์ž…๋ ฅ ์ˆœ์„œ ๋ณด์žฅํ—ˆ์šฉ
Set์ง‘ํ•ฉ (์ˆœ์„œ๋ณด๋‹ค ์œ ๋‹ˆํฌํ•œ ๊ฐ’์ด ์ค‘์š”)์ˆœ์„œ ์—†์Œ (LinkedHashSet, TreeSet์€ ์˜ˆ์™ธ)ํ—ˆ์šฉ์•ˆํ•จ
Queue๋Œ€๊ธฐ์—ด (FIFO)์ž…๋ ฅ ์ˆœ์„œ ๋ณด์žฅํ—ˆ์šฉ
Deque์–‘์ชฝ ๋์ด ๋šซ๋ฆฐ ํ (Stack + Queue)์ž…๋ ฅ ์ˆœ์„œ ๋ณด์žฅ (์–‘์ชฝ ๋์—์„œ ์กฐ์ž‘ ๊ฐ€๋Šฅ)ํ—ˆ์šฉ

Map ์ธํ„ฐํŽ˜์ด์Šค

Map์€ ํ‚ค(Key)๋ฅผ ๊ฐ’(Value)์— ๋งคํ•‘ํ•˜๋Š” ๊ฐ์ฒด๋‹ค. ํ‚ค๋Š” ์ค‘๋ณต๋  ์ˆ˜ ์—†์œผ๋ฉฐ ํ•˜๋‚˜์˜ ํ‚ค๋Š” ํ•˜๋‚˜์˜ ๊ฐ’์—๋งŒ ๋งคํ•‘๋œ๋‹ค. Collection ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†๋ฐ›์ง€๋Š” ์•Š์ง€๋งŒ keySet(), values(), entrySet() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ปฌ๋ ‰์…˜ ๋ทฐ๋ฅผ ์ œ๊ณตํ•จ์œผ๋กœ์จ ์ปฌ๋ ‰์…˜๊ณผ ์œ ๊ธฐ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋œ๋‹ค.

๋ ˆ๊ฑฐ์‹œ ์ปฌ๋ ‰์…˜

์ดˆ๊ธฐ๋ฒ„์ „ (JDK 1.0)์—์„œ ์‚ฌ์šฉ๋˜๋˜ Vector, Stack, Hashtable๊ณผ ๊ฐ™์€ ํด๋ž˜์Šค๋„ ์—ฌ์ „ํžˆ ์กด์žฌํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋“ค์€ ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— ๋™๊ธฐํ™”(Synchronized)๊ฐ€ ๊ฑธ๋ ค ์žˆ์–ด ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์ด ์•„๋‹Œ ๊ณณ์—์„œ๋Š” ๋ถˆํ•„์š”ํ•œ ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ์œ ๋ฐœํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ํ˜„์žฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋Œ€์ฒดํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋œ๋‹ค.

๋ ˆ๊ฑฐ์‹œ๋Œ€์ฒดํด๋ž˜์Šค์„ค๋ช…
VectorArrayList๋™๊ธฐํ™” ์ œ๊ฑฐ, ์„ฑ๋Šฅ ์ด์ 
HashTableHashMap๋™๊ธฐํ™” ์ œ๊ฑฐ, null ํ‚ค/๊ฐ’ ํ—ˆ์šฉ
StackArrayDeque์ผ๊ด€๋œ API, ์„ฑ๋Šฅ ์šฐ์ˆ˜

Vector -> ArrayList, HashTable -> HashMap, Stack -> ArrayDeque ๋Œ€์ฒด๋Š” ๋ถˆํ•„์š”ํ•œ ๋™๊ธฐํ™” ๋กœ์ง์„ ์ œ๊ฑฐํ•จ์œผ๋กœ์จ ์„ฑ๋Šฅ์ƒ์˜ ์ด์ ์„ ๊ฐ€์ ธ์˜ค์ง€๋งŒ ์Šค๋ ˆ๋“œ ์•ˆ์ „ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์€ ์œ„ํ—˜ํ•˜๋‹ค.
์ด ๊ฒฝ์šฐ์—๋Š” java.util.concurrent ํŒจํ‚ค์ง€์˜ ํด๋ž˜์Šค๋“ค์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

List ์ธํ„ฐํŽ˜์ด์Šค

๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” List ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด์ธ ArrayList์™€ LinkedList๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ์„ ์ขŒ์šฐํ•˜๋Š” ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด๋‹ค.

ArrayList

ArrayList๋Š” ์ด๋ฆ„ ๊ทธ๋Œ€๋กœ ๋ฐฐ์—ด(Array)์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ๋ฆฌ์ŠคํŠธ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ Object elementData๋ผ๋Š” ๋ฐฐ์—ด์„ ๊ฐ€์ง€๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.
์ž๋ฐ”์˜ ๋ฐฐ์—ด์€ ์ƒ์„ฑ์‹œ ํฌ๊ธฐ๊ฐ€ ๊ณ ์ •๋˜์ง€๋งŒ ArrayList๋Š” ๋™์ ์œผ๋กœ ํฌ๊ธฐ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฒ˜์Œ ์„ค์ •ํ•œ capacity๊ฐ€ ์ฐจ๋ฉด ๋” ํฐ ๋ฐฐ์—ด์„ ์ƒˆ๋กœ ๋งŒ๋“ค๊ณ  ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ์›๋ฆฌ๋‹ค. ์ด ๋•Œ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ์–ผ๋งˆ๋‚˜ ๋” ํฌ๊ฒŒ ๋งŒ๋“ค๊ฒƒ์ธ๊ฐ€๊ฐ€ ์ค‘์š”ํ•œ๋ฐ JDK์˜ ArrayList๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ 1.5๋ฐฐ(50%)์”ฉ ํฌ๊ธฐ๋ฅผ ๋Š˜๋ฆฐ๋‹ค.

old Capacity + (oldCapacity >> 1)
Java

ArrayList์˜ ๊ฐ€์žฅ ํฐ ์žฅ์ ์€ ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•œ ์กฐํšŒ ์†๋„๊ฐ€ O(1)์ด๋ผ๋Š” ์ ์ด๋‹ค. ๋ฐฐ์—ด์€ ๋ฉ”๋ชจ๋ฆฌ ์ƒ์—์„œ ์—ฐ์†์ ์œผ๋กœ ์œ„์น˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ธ๋ฑ์Šค์˜ ์ฃผ์†Œ๋ฅผ ์‹œ์ž‘ ์ฃผ์†Œ + (์ธ๋ฑ์Šค * ๋ฐ์ดํ„ฐ ํฌ๊ธฐ)๋ผ๋Š” ๋‹จ์ˆœํ•œ ์ˆ˜์‹์œผ๋กœ ์œ„์น˜๋ฅผ ๋ฐ”๋กœ ์ฐพ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ 100๊ฐœ๋“  100๋งŒ๊ฐœ๋“  ์กฐํšŒ ์†๋„๊ฐ€ ๋™์ผํ•จ์„ ์˜๋ฏธํ•œ๋‹ค.

LinkedList

LinkedList๋Š” ๋ชจ๋“  ๋…ธ๋“œ๋“ค์ด ์„œ๋กœ ์—ฐ๊ฒฐ๋œ ๊ตฌ์กฐ๋‹ค. ๊ฐ ๋…ธ๋“œ๋Š” ๋ฐ์ดํ„ฐ์™€ ๋‹ค์Œ ๋…ธ๋“œ์˜ ์ฃผ์†Œ(next), ์ด์ „ ๋…ธ๋“œ์˜ ์ฃผ์†Œ(prev)๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. (Doublely Linked List)
LinkedList๋Š” ์ค‘๊ฐ„์— ์‚ฝ์ž…/์‚ญ์ œ๊ฐ€ ๋น ๋ฅด๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ArrayList๋Š” ์ค‘๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์œผ๋ ค๋ฉด ๋’ค์˜ ๋ฐ์ดํ„ฐ๋“ค์„ ํ•œ์นธ์”ฉ ๋ฐ€์–ด์•ผ ํ•ด์„œ O(n)์ด ๊ฑธ๋ฆฌ์ง€๋งŒ LinkedList๋Š” ์•ž๋’ค ๋…ธ๋“œ์˜ ์—ฐ๊ฒฐ ๊ณ ๋ฆฌ๋งŒ ๋ฐ”๊ฟ”์ฃผ๋ฉด ๋˜๋ฏ€๋กœ O(1)์ด ๊ฑธ๋ฆฐ๋‹ค.
ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์—๋Š” ํ•จ์ •์ด ์žˆ๋‹ค.
ํ˜„๋Œ€์˜ ์ปดํ“จํ„ฐ ์•„ํ‚คํ…์ฒ˜์—์„œ CPU๋Š” ๋ฉ”๋ชจ๋ฆฌ(RAM)์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ํ•˜๋‚˜๋งŒ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ณ  ์บ์‹œ ๋ผ์ธ(Cache Line) ์ด๋ผ๋Š” ๋‹จ์œ„(๋ณดํ†ต 64๋ฐ”์ดํŠธ)๋กœ ์ฃผ๋ณ€ ๋ฐ์ดํ„ฐ๊นŒ์ง€ ๋ฉ์–ด๋ฆฌ๋กœ ๊ฐ€์ ธ์™€ CPU ๋‚ด๋ถ€์˜ ์บ์‹œ์— ์ €์žฅํ•œ๋‹ค. (Cache Locality)

  • ArrayList์˜ ๊ฒฝ์šฐ: ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์—ฐ์†์ ์œผ๋กœ ์ €์žฅ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ ๋’ค์˜ ์š”์†Œ๋“ค๋„ ํ•จ๊ป˜ ์บ์‹œ๋กœ ๋”ธ๋ ค์˜จ๋‹ค. ์ˆœ์ฐจ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ๋•Œ ์ด๋ฏธ ๋ฐ์ดํ„ฐ๊ฐ€ ์บ์‹œ์— ์žˆ์„ ํ™•๋ฅ ์ด ๋†’๊ธฐ ๋•Œ๋ฌธ์— ๋น ๋ฅด๋‹ค.
  • LinkedList์˜ ๊ฒฝ์šฐ: ๋ฐ์ดํ„ฐ(๋…ธ๋“œ)๊ฐ€ ํž™ ๋ฉ”๋ชจ๋ฆฌ์˜ ์ด๊ณณ์ €๊ณณ์— ํฉ์–ด์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋…ผ๋ฆฌ์ ์œผ๋กœ๋Š” ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€๋งŒ ๋ฌผ๋ฆฌ์ ์œผ๋กœ๋Š” ๋ฉ€๋ฆฌ ๋–จ์–ด์ ธ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹ค์Œ ๋…ธ๋“œ๋กœ ์ด๋™ํ•  ๋•Œ๋งˆ๋‹ค CPU๋Š” ์บ์‹œ์— ์—†๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ƒˆ๋กœ ๊ฐ€์ ธ์™€์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋กœ ์ธํ•ด CPU ํŒŒ์ดํ”„๋ผ์ธ์ด ๋ฉˆ์ถ”๊ณ  ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ๋‹ค.

์‹ค์ œ ๋ฒค์น˜๋งˆํฌ๋ฅผ ๋Œ๋ ค๋ณด๋ฉด ์š”์†Œ์˜ ์‚ฝ์ž…/์‚ญ์ œ์กฐ์ฐจ๋„ ๋ฆฌ์ŠคํŠธ์˜ ํฌ๊ธฐ๊ฐ€ ์—„์ฒญ๋‚˜๊ฒŒ ํฌ์ง€ ์•Š์€ ์ด์ƒ ArrayList๊ฐ€ LinkedList๋ณด๋‹ค ๋น ๋ฅธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. LinkedList์—์„œ ์‚ฝ์ž… ์œ„์น˜๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ํƒ์ƒ‰ํ•˜๋Š” ๊ณผ์ • ์ž์ฒด๊ฐ€ O(n)์ด๋ฉฐ ์ด ํƒ์ƒ‰ ๊ณผ์ •์—์„œ ์บ์‹œ ํšจ์œจ์ด ๋‚˜์˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ ํŠน๋ณ„ํ•œ ์ด์œ ๊ฐ€ ์—†๋‹ค๋ฉด ํ•ญ์ƒ ArrayList๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

์œ„ ๋‚ด์šฉ์€ ์•„๋ž˜ ๋งํฌ๋“ค์„ ์ฐธ๊ณ ํ•˜๊ธฐ ๋ฐ”๋ž€๋‹ค.

https://stackoverflow.com/questions/79594341/arraylist-vs-linkedlist-in-terms-of-cache-locality
https://www.geeksforgeeks.org/dsa/why-arrays-have-better-cache-locality-than-linked-list/
https://can-ozkan.medium.com/arraylist-vs-linkedlist-88022088fdef

Map๊ณผ Set์˜ ๋‚ด๋ถ€

๋ฐ์ดํ„ฐ์˜ ์œ ์ผ์„ฑ์„ ๋ณด์žฅํ•˜๋Š” Set๊ณผ ํ‚ค-๊ฐ’์Œ์„ ๊ด€๋ฆฌํ•˜๋Š” Map์€ ๋‚ด๋ถ€์ ์œผ๋กœ ์œ ์‚ฌํ•œ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง„๋‹ค. ์‚ฌ์‹ค HashSet์€ ๋‚ด๋ถ€์ ์œผ๋กœ HashMap์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„๋˜์–ด ์žˆ๊ณ  Set์˜ ๊ฐ’์€ HashMap์˜ ํ‚ค๋กœ ์ €์žฅ๋˜๊ณ  HashMap์˜ ๊ฐ’์€ PRESENT๋ผ๋Š” ๋”๋น„ ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค. ๋‹ค์Œ์€ HashSet ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜ ์„ ์–ธ๋ถ€๋ถ„์ด๋‹ค.

private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
Java

HashMap์˜ ์ง„ํ™”: LinkedList์—์„œ Red-Black ํŠธ๋ฆฌ๋กœ

HashMap์€ ํ•ด์‹œ ๋ฒ„ํ‚ท(Hash Bucket)์ด๋ผ๋Š” ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•œ๋‹ค. ํ•ด์‹œ ๋ฒ„ํ‚ท์€ ํ•ด์‹œ ํ…Œ์ด๋ธ”(HashMap)์˜ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ด ๋˜๋Š” ์ €์žฅ์†Œ ๋‹จ์œ„๋ฅผ ๋งํ•œ๋‹ค. ์‰ฝ๊ฒŒ ๋งํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ์‹ค์ œ๋กœ ๋‹ด๊ธฐ๋Š” ์„œ๋ž์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. HashMap์€ ๋‚ด๋ถ€์ ์œผ๋กœ ๊ฑฐ๋Œ€ํ•œ ๋ฐฐ์—ด์„ ํ•˜๋‚˜ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋ฐ ์ด ๋ฐฐ์—ด์˜ ๊ฐ ์นธ(์ธ๋ฑ์Šค) ํ•˜๋‚˜ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ ๋ฒ„ํ‚ท์ด๋‹ค. ์ด ๋ฒ„ํ‚ท ์•ˆ์—์„œ ์–ด๋–ค ์ผ์ด ๋ฒŒ์–ด์ง€๋Š”์ง€ ํŠนํžˆ ํ•ด์‹œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ž๋ฐ”๊ฐ€ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ์•„๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

ํ•ด์‹œ ๋ฒ„ํ‚ท(Hash Bucket)์˜ ๊ธฐ๋ณธ๊ตฌ์กฐ

map.put(“key”, “value”)๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ผ์ด ์ผ์–ด๋‚œ๋‹ค.

  1. ํ•ด์‹œ ๊ณ„์‚ฐ: ํ‚ค(“key”)์˜ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๊ตฌํ•œ๋‹ค.
  2. ์ฃผ์†Œ ๋ฐฐ์ •: ๊ทธ ์ˆซ์ž๋ฅผ ๋ฐฐ์—ด์˜ ํฌ๊ธฐ๋กœ ๋‚˜๋ˆˆ ๋‚˜๋จธ์ง€๋ฅผ ๊ตฌํ•ด ๋ช‡ ๋ฒˆ์งธ ๋ฒ„ํ‚ท์— ๋„ฃ์„์ง€ ์ •ํ•œ๋‹ค. (์˜ˆ: 3๋ฒˆ ๋ฒ„ํ‚ท)
  3. ์ €์žฅ: 3๋ฒˆ์งธ ๋ฒ„ํ‚ท์— ๊ฐ€์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๋Š”๋‹ค. ์ด๋•Œ 3๋ฒˆ ๋ฒ„ํ‚ท์ด ๋น„์–ด์žˆ๋‹ค๋ฉด ๋ฌธ์ œ ์—†์ง€๋งŒ ์ด๋ฏธ ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•œ๋‹ค.

ํ•ด์‹œ ์ถฉ๋Œ

์„œ๋กœ ๋‹ค๋ฅธ ํ‚ค์ธ๋ฐ ๊ณ„์‚ฐ๋œ ํ•ด์‹œ ๊ฐ’์ด ๊ฐ™์•„ ์ฃผ์†Œ๊ฐ€ ๊ฐ™์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ•ด์‹œ ์ถฉ๋Œ์ด๋ผ๊ณ  ํ•œ๋‹ค. ์ด ๋•Œ ๋ฒ„ํ‚ท์€ ๋‹จ์ˆœํ•œ ๋ณ€์ˆ˜์—์„œ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ๋ณ€์‹ ํ•œ๋‹ค.
์ž๋ฐ”(HashMap)์—์„œ๋Š” Seperate Chaining ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ๋ฒ„ํ‚ท ๋‚ด๋ถ€ ๊ตฌ์กฐ๋Š” ๋ฐ์ดํ„ฐ ์–‘์— ๋”ฐ๋ผ ๋‘ ๊ฐ€์ง€๋กœ ๋‚˜๋‰œ๋‹ค.

LinkedList (๋ฐ์ดํ„ฐ๊ฐ€ ์ ์„ ๋•Œ)

ํ•œ ๋ฒ„ํ‚ท์— ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฒน์น˜๋ฉด LinkedList๋กœ ์—ฎ์–ด์„œ ์ €์žฅํ•œ๋‹ค.

  • ๊ตฌ์กฐ: A -> B -> C
  • ์กฐํšŒ ์†๋„: O(n) (์ตœ์•…์˜ ๊ฒฝ์šฐ ๋ฆฌ์ŠคํŠธ ๋๊นŒ์ง€ ๋‹ค ๋’ค์ ธ์•ผํ•จ)
  • ์‚ฌ์šฉ ์‹œ์ : ๋ฒ„ํ‚ท ํ•˜๋‚˜์— ๋ฐ์ดํ„ฐ๊ฐ€ 8๊ฐœ ๋ฏธ๋งŒ์ผ ๋•Œ
Red-Black ํŠธ๋ฆฌ (๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์„ ๋•Œ)

์ž๋ฐ” 8์—์„œ ๋„์ž…๋œ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋กœ ๊ฐœ์„ ๋œ ๋ฐฉ์‹์ด๋‹ค. ํ•œ ๋ฒ„ํ‚ท์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์ด ์Œ“์ด๋ฉด(8๊ฐœ ์ด์ƒ) ์กฐํšŒ ์†๋„๊ฐ€ ๋А๋ ค์ง€๋Š” LinkedList๋ฅผ ๋ฒ„๋ฆฌ๊ณ  ํŠธ๋ฆฌ(Tree)๊ตฌ์กฐ๋กœ ๋ฆฌ๋ชจ๋ธ๋ง ํ•œ๋‹ค.

  • ๊ตฌ์กฐ: ๊ท ํ˜•์žกํžŒ ์ด์ง„ํŠธ๋ฆฌ (์ •๋ ฌ๋œ ์ƒํƒœ ์œ ์ง€)
  • ์กฐํšŒ ์†๋„: O(log N) (๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋ฌด๋ฆฌ ๋งŽ์•„๋„ ํ›จ์”ฌ ๋น ๋ฅด๋‹ค)
  • ์‚ฌ์šฉ ์‹œ์ : ๋ฒ„ํ‚ท ํ•˜๋‚˜์— ๋ฐ์ดํ„ฐ๊ฐ€ 8๊ฐœ ์ด์ƒ ์Œ“์ผ ๋•Œ (๋‹ค์‹œ 6๊ฐœ ์ดํ•˜๋กœ ์ค„์–ด๋“ค๋ฉด ๋ฆฌ์ŠคํŠธ๋กœ ๋Œ์•„๊ฐ„๋‹ค.)

HashMap ํด๋ž˜์Šค์— Threshold ์ƒ์ˆ˜๊ฐ’์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜ ๋˜์–ด ์žˆ๋‹ค.

/**
 * The bin count threshold for using a tree rather than list for a
 * bin.  Bins are converted to trees when adding an element to a
 * bin with at least this many nodes. The value must be greater
 * than 2 and should be at least 8 to mesh with assumptions in
 * tree removal about conversion back to plain bins upon
 * shrinkage.
 */
static final int TREEIFY_THRESHOLD = 8;

/**
 * The bin count threshold for untreeifying a (split) bin during a
 * resize operation. Should be less than TREEIFY_THRESHOLD, and at
 * most 6 to mesh with shrinkage detection under removal.
 */
static final int UNTREEIFY_THRESHOLD = 6;
Java

์ด๋Ÿฌํ•œ ๊ตฌ์กฐ ๋•๋ถ„์— HashMap์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋ฌด๋ฆฌ ๋งŽ์ด ๋“ค์–ด์™€๋„ ๊ฝค ๊ดœ์ฐฎ์€ ๊ฒ€์ƒ‰ ์†๋„๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

LinkedHashMap / LinedkHashSet

LinkedHashMap๊ณผ LinkedHashSet์€ ๊ธฐ์กด HashMap ๊ธฐ๋Šฅ์— ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์€ ํ•ด์‹œ ํ…Œ์ด๋ธ”(Hash Table)์ด์ง€๋งŒ ๋ฐ์ดํ„ฐ ๋ผ๋ฆฌ์˜ ์ˆœ์„œ๋Š” link๋กœ ๋ฌถ์–ด์„œ ์ˆœ์„œ๋ฅผ ๊ธฐ์–ตํ•˜๋„๋ก ํ•˜๋Š” ๊ตฌ์กฐ๋‹ค.

LinkedHashMap์˜ ๋…ธ๋“œ ๊ตฌ์กฐ

์ผ๋ฐ˜์ ์ธ HashMap์˜ ๋…ธ๋“œ๋Š” 4๊ฐœ์˜ ํ•„๋“œ๋ฅผ ๊ฐ€์ง„๋‹ค. ํ•˜์ง€๋งŒ LinkedHashMap์€ ์ˆœ์„œ๋ฅผ ๊ธฐ์–ตํ•˜๊ธฐ ์œ„ํ•ด์„œ 2๊ฐœ์˜ ํ•„๋“œ๋ฅผ ๋” ๊ฐ€์ง„๋‹ค.

  • HashMap Node: Hash, Key, Value, Next
  • LinkedHashMap Entry: HashMap Node + Before, After

Before์™€ After๊ฐ€ ๋ฐ”๋กœ ‘๋‚˜๋ณด๋‹ค ๋จผ์ € ๋“ค์–ด์˜จ ๋†ˆ’, ‘๋‚˜ ๋‹ค์Œ์— ๋“ค์–ด์˜จ ๋†ˆ’์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋งํฌ ์—ญํ• ์„ ํ•œ๋‹ค.
LinkedHashMap์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜๋˜์–ด ์žˆ๋‹ค.
Node์˜ Next๋Š” ๋™์ผ ๋ฒ„ํ‚ท์—์„œ ์—ฌ๋Ÿฌ ๋…ธ๋“œ๊ฐ€ ์žˆ์„ ๋•Œ(LinkedList ํ˜น์€ RB Tree) ํ•ด๋‹น ๋ฒ„ํ‚ท ๋‚ด์—์„œ์˜ ๋งํฌ๋ฅผ ์˜๋ฏธํ•˜๊ณ  Before, After๋Š” ๋ฒ„ํ‚ท๊ณผ ์ƒ๊ด€์—†์ด ์ด์ „๊ณผ ์ดํ›„์— ์ž…๋ ฅ๋œ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฅดํ‚จ๋‹ค.

static class Entry<K,V> extends HashMap.Node<K,V> {
    Entry<K,V> before, after;
    Entry(int hash, K key, V value, Node<K,V> next) {
        super(hash, key, value, next);
    }
}
Java

LinkedHashMap์€ ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

  1. ๊ฒ€์ƒ‰ (Hash Table) – HashMap๊ณผ ๋™์ผ
    • Key์˜ ํ•ด์‹œ ๊ฐ’์„ ๊ณ„์‚ฐํ•ด์„œ ๋ฒ„ํ‚ท(๋ฐฐ์—ด)์˜ ์œ„์น˜๋ฅผ ์ฐพ๋Š”๋‹ค.
    • ๋ฒ„ํ‚ท์˜ ์œ„์น˜๋ฅผ ๋ฐ”๋กœ ์ฐพ์œผ๋ฏ€๋กœ O(1)์˜ ์„ฑ๋Šฅ์„ ๊ฐ–๋Š”๋‹ค. (๋ฒ„ํ‚ท ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ๋Š” O(log n))
    • HashMap๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ถฉ๋Œ์ด ๋‚˜๋ฉด Next๋กœ ์—ฐ๊ฒฐ๋˜๊ฑฐ๋‚˜ Red-Black Tree๊ฐ€ ๋œ๋‹ค.
  2. ์ˆœ์„œ ๋ณด์žฅ (Doubly Linked List)
    • ๋ชจ๋“  ๋ฐ์ดํ„ฐ(๋…ธ๋“œ)๋“ค์ด ์ž…๋ ฅ๋œ ์ˆœ์„œ๋Œ€๋กœ Head ๋ถ€ํ„ฐ Tail๊นŒ์ง€ ํ•˜๋‚˜์˜ ๊ธด ์ค„๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค.
    • ์ „์ฒด๋ฅผ ์ˆœํšŒ(Iteration)ํ•  ๋•Œ๋Š” ์ด ๊ธธ์„ ๋”ฐ๋ผ๊ฐ์œผ๋กœ์จ ์ž…๋ ฅ ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•œ๋‹ค.

LinkedHashSet

HashSet์ด HashMap์˜ ๊ป๋ฐ๊ธฐ์˜€๋˜ ๊ฒƒ์ฒ˜๋Ÿผ LinkedHashSet์€ LinkedHashMap์˜ ๊ป๋ฐ๊ธฐ ์—ญํ• ์„ ํ•œ๋‹ค.

  • ๋‚ด๋ถ€์ ์œผ๋กœ LinkedHashMap์„ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๋ฐ์ดํ„ฐ๋Š” Key์— ์ €์žฅํ•˜๊ณ  Value๋Š” ๋”๋ฏธ ๊ฐ์ฒด(PRESENT)๋ฅผ ๋„ฃ๋Š” ๋ฐฉ์‹์ด ์™„์ „ํžˆ ๋™์ผํ•˜๋‹ค.
  • ๊ตฌ์กฐ์ ์œผ๋กœ LinkedHashMap๊ณผ ๋™์ผํ•˜๋‹ค.
  • ์ž…๋ ฅ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•˜๊ณ  ์ค‘๋ณต์„ ๋ฐฉ์ง€ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.

TreeMap / TreeSet

TreeMap๊ณผ TreeSet์€ ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ๋‚ด๋ถ€์ ์œผ๋กœ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ Red-Black Tree๋กœ๋งŒ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค. TreeMap์€ ๋ฒ„ํ‚ท์ด๋‚˜ ํ•ด์‹œ ํ•จ์ˆ˜ ๊ฐ™์€๊ฑด ์•„์˜ˆ ์—†๊ณ  ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ํ•˜๋‚˜์˜ ๊ฑฐ๋Œ€ํ•œ Red-Black Tree๋กœ ์ €์žฅ๋œ๋‹ค.
TreeMap์€ ํ‚ค๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋น„๊ต ์—ฐ์‚ฐ์ž๋ฅผ ํ†ตํ•ด์„œ ์ •๋ ฌ๋˜์–ด ์ €์žฅ๋œ๋‹ค.

๋‚ด๋ถ€๊ตฌ์กฐ

TreeMap์˜ ๋‚ด๋ถ€๋Š” ๋ฐฐ์—ด ์—†์ด ๋ฃจํŠธ ๋…ธ๋“œ ํ•˜๋‚˜์—์„œ ์‹œ์ž‘ํ•ด์„œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ€์ง€์น˜๊ธฐํ•˜๋“ฏ ์—ฐ๊ฒฐ๋œ ๊ตฌ์กฐ๋‹ค.

  • ์ €์žฅ ๋ฐฉ์‹: ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์„ ๋•Œ๋งˆ๋‹ค ์ •๋ ฌ ๊ธฐ์ค€(ํฌ๊ธฐ)์— ๋งž์ถฐ์„œ ์™ผ์ชฝ(์ž‘์€๊ฐ’)์ด๋‚˜ ์˜ค๋ฅธ์ชฝ(ํฐ๊ฐ’) ์ž์‹์œผ๋กœ ์ฐพ์•„ ๊ฐ„๋‹ค.
  • ๊ท ํ˜• ์œ ์ง€: ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ์ฆ‰์‹œ ์ƒ‰๊น”์„ ์น ํ•˜๊ณ  ํšŒ์ „(Rotation)ํ•ด์„œ ํŠธ๋ฆฌ์˜ ๋†’์ด๋ฅผ logN์œผ๋กœ ๋งž์ถ˜๋‹ค.
  • TreeSet: ์—ญ์‹œ HashSet๊ณผ ๊ฐ™์ด ๊ป๋ฐ๊ธฐ์ผ ๋ฟ์ด๊ณ  ๋‚ด๋ถ€๋Š” TreeMap์„ ์‚ฌ์šฉํ•œ๋‹ค.

ํ•ต์‹ฌ ์ฐจ์ด: ํ•ด์‹œ vs ๋น„๊ต

TreeMap์€ hashCode()์™€ equals()๋ฅผ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ตฌ๋ถ„HashMap / HashSetTreeMap / TreeSet
์‹๋ณ„ ๋„๊ตฌhashCode(), equals()compareTo() (๋˜๋Š” Comparator)
์ €์žฅ ์œ„์น˜ํ•ด์‹œ ๊ฐ’์œผ๋กœ ๊ณ„์‚ฐ๋œ ๋ฒ„ํ‚ท ์ฃผ์†Œํฌ๊ธฐ ๋น„๊ต๋ฅผ ํ†ตํ•ด ๊ฒฐ์ •๋œ ํŠธ๋ฆฌ ์œ„์น˜
์ •๋ ฌ๋ถˆ๊ฐ€๋Šฅ (๋’ค์ฃฝ๋ฐ•์ฃฝ)์ž๋™ ์ •๋ ฌ(์˜ค๋ฆ„์ฐจ์ˆœ ๊ธฐ๋ณธ)
Null Key1๊ฐœ ํ—ˆ์šฉ๋ถˆ๊ฐ€ (๋น„๊ตํ•ด์•ผ ํ•˜๋Š”๋ฐ null์ด๋ฉด ์—๋Ÿฌ)

TreeMap์— ๊ฐ์ฒด๋ฅผ ๋„ฃ์œผ๋ ค๋ฉด ๊ทธ ๊ฐ์ฒด๋Š” ๋ฐ˜๋“œ์‹œ Comparable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค.
(์•„๋‹ˆ๋ฉด ์ƒ์„ฑ์ž์— ๋ณ„๋„์˜ Comparator๋ฅผ ๋„ฃ์–ด์ค˜์•ผ ํ•œ๋‹ค)
๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ •๋ ฌ ๋ฐฉ๋ฒ•์„ ์•Œ ์ˆ˜ ์—†์–ด ์—๋Ÿฌ(ClassCastException)๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

TreeMap์€ ์–ธ์ œ ์‚ฌ์šฉํ•˜๋‚˜?

๋‹จ์ˆœํžˆ ๋ฐ์ดํ„ฐ ์ €์žฅ์ด ๋ชฉ์ ์ด๋ผ๋ฉด ๋ฌด์กฐ๊ฑด HashMap์ด ๋‚ซ๋‹ค. ํ•˜์ง€๋งŒ ์ˆœ์„œ๋‚˜ ๋ฒ”์œ„๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋Š” TreeMap์ด ์••๋„์ ์ด๋‹ค.

  1. ์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•  ๋•Œ
    • ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๊ธฐ๋งŒ ํ•˜๋ฉด ์•Œ์•„์„œ ๊ฐ€๋‚˜๋‹ค์ˆœ(ํ˜น์€ ์ง€์ •ํ•œ ์ˆœ์„œ)์œผ๋กœ ์ •๋ ฌ๋œ๋‹ค. Collections.sort()๋ฅผ ํ˜ธ์ถœํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
  2. ๋ฒ”์œ„ ๊ฒ€์ƒ‰(Range Search)
    • “20๋Œ€ ํšŒ์›๋งŒ ๊ฐ€์ ธ์™€”, “์ด๋ฆ„์ด ‘๊น€’์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ์‚ฌ๋žŒ๋งŒ ์ฐพ์•„์ค˜” ๊ฐ™์€ ์ฟผ๋ฆฌ์— ์ตœ์ ํ™” ๋˜์–ด ์žˆ๋‹ค.
    • ๋ฉ”์„œ๋“œ: subMap(), headMap(), tailMap()
  3. ๊ฐ€๊นŒ์šด ๊ฐ’ ์ฐพ๊ธฐ
    • ์ •ํ™•ํžˆ 100์€ ์—†๋Š”๋ฐ 100์ด๋ž‘ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ํฐ ์ˆ˜๋Š” ๋ญ”๊ฐ€?
    • ๋ฉ”์„œ๋“œ: ceilingEntry() (ํฌ๊ฑฐ๋‚˜ ๊ฐ™์€), floorEntry() (์ž‘๊ฑฐ๋‚˜ ๊ฐ™์€), higherEntry(), lowerEntry()

์ƒ˜ํ”Œ ์ฝ”๋“œ

๋‹ค์Œ์€ TreeMap์„ ์‚ฌ์šฉํ•˜๋Š” ์ƒ˜ํ”Œ ์ฝ”๋“œ๋‹ค. ์ •๋ ฌ, ๋ฒ”์œ„ ์ถ”์ถœ๋“ฑ๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ์†์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

@Test
void treeMapTest() {
    // 1. TreeMap ์ƒ์„ฑ (๊ธฐ๋ณธ์€ Key ๊ธฐ์ค€ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ)
    // ์—ญ์ˆœ(ํฐ ์ ์ˆ˜๊ฐ€ ๋จผ์ €)์œผ๋กœ ํ•˜๋ ค๋ฉด new TreeMap<>(Collections.reverseOrder()) ์‚ฌ์šฉ
    TreeMap<Integer, String> ranking = new TreeMap<>();

    // 2. ๋ฐ์ดํ„ฐ ๋ฌด์ž‘์œ„ ์ž…๋ ฅ (๋„ฃ๋Š” ์ˆœ์„œ๋Š” ์ƒ๊ด€์—†์Œ, ์•Œ์•„์„œ ์ •๋ ฌ๋จ)
    ranking.put(50, "ํ›ˆ์ด");
    ranking.put(95, "์ฒ ์ˆ˜");
    ranking.put(10, "๋งน๊ตฌ");
    ranking.put(88, "์˜ํฌ");
    ranking.put(72, "์งฑ๊ตฌ");

    System.out.println("=== 1. ์ „์ฒด ๋žญํ‚น (์ž๋™ ์ •๋ ฌ๋จ) ===");
    // HashMap์ด์—ˆ๋‹ค๋ฉด ๋’ค์ฃฝ๋ฐ•์ฃฝ ๋‚˜์™”๊ฒ ์ง€๋งŒ, ์—ฌ๊ธด ์ ์ˆ˜์ˆœ์œผ๋กœ ๋‚˜์˜ด
    ranking.forEach((score, name) ->
            System.out.println(score + "์ : " + name)
    );


    System.out.println("\n=== 2. ํŠน์ • ์ ์ˆ˜ ๊ตฌ๊ฐ„ ๊ฒ€์ƒ‰ (subMap) ===");
    // subMap(์‹œ์ž‘์ , ํฌํ•จ์—ฌ๋ถ€, ๋์ , ํฌํ•จ์—ฌ๋ถ€)
    // 70์  ์ด์ƒ ~ 90์  ๋ฏธ๋งŒ์ธ ์œ ์ €๋งŒ ์™ ๋ฝ‘์•„๋ƒ„
    NavigableMap<Integer, String> silverTier = ranking.subMap(70, true, 90, false);

    System.out.println("์‹ค๋ฒ„ ํ‹ฐ์–ด(70~89์ ): " + silverTier);


    System.out.println("\n=== 3. ๊ทผ์ ‘๊ฐ’ ์ฐพ๊ธฐ (๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ!) ===");
    int myScore = 80;

    // floorEntry: 80์ ๊ณผ ๊ฐ™๊ฑฐ๋‚˜, ์—†์œผ๋ฉด ๋ฐ”๋กœ ์•„๋ž˜ ์ ์ˆ˜ (๋‚ด๋ฆผ)
    Map.Entry<Integer, String> lower = ranking.floorEntry(myScore);
    // ceilingEntry: 80์ ๊ณผ ๊ฐ™๊ฑฐ๋‚˜, ์—†์œผ๋ฉด ๋ฐ”๋กœ ์œ„ ์ ์ˆ˜ (์˜ฌ๋ฆผ)
    Map.Entry<Integer, String> higher = ranking.ceilingEntry(myScore);

    System.out.println("๋‚ด ์ ์ˆ˜(" + myScore + ") ๋ฐ”๋กœ ์•„๋ž˜ ๋ผ์ด๋ฒŒ: " + lower.getKey() + "์  (" + lower.getValue() + ")");
    System.out.println("๋‚ด ์ ์ˆ˜(" + myScore + ") ๋ฐ”๋กœ ์œ„ ๋ผ์ด๋ฒŒ: " + higher.getKey() + "์  (" + higher.getValue() + ")");


    System.out.println("\n=== 4. 1๋“ฑ๊ณผ ๊ผด์ฐŒ ๊ตฌํ•˜๊ธฐ ===");
    System.out.println("1๋“ฑ(์ตœ๊ณ ์ ): " + ranking.lastEntry()); // Key๊ฐ€ ๊ฐ€์žฅ ํฐ ๋†ˆ
    System.out.println("๊ผด์ฐŒ(์ตœ์ €์ ): " + ranking.firstEntry()); // Key๊ฐ€ ๊ฐ€์žฅ ์ž‘์€ ๋†ˆ
}
Java

์‹คํ–‰๊ฒฐ๊ณผ

=== 1. ์ „์ฒด ๋žญํ‚น (์ž๋™ ์ •๋ ฌ๋จ) ===
10์ : ๋งน๊ตฌ
50์ : ํ›ˆ์ด
72์ : ์งฑ๊ตฌ
88์ : ์˜ํฌ
95์ : ์ฒ ์ˆ˜

=== 2. ํŠน์ • ์ ์ˆ˜ ๊ตฌ๊ฐ„ ๊ฒ€์ƒ‰ (subMap) ===
์‹ค๋ฒ„ ํ‹ฐ์–ด(70~89์ ): {72=์งฑ๊ตฌ, 88=์˜ํฌ}

=== 3. ๊ทผ์ ‘๊ฐ’ ์ฐพ๊ธฐ (๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ!) ===
๋‚ด ์ ์ˆ˜(80) ๋ฐ”๋กœ ์•„๋ž˜ ๋ผ์ด๋ฒŒ: 72์  (์งฑ๊ตฌ)
๋‚ด ์ ์ˆ˜(80) ๋ฐ”๋กœ ์œ„ ๋ผ์ด๋ฒŒ: 88์  (์˜ํฌ)

=== 4. 1๋“ฑ๊ณผ ๊ผด์ฐŒ ๊ตฌํ•˜๊ธฐ ===
1๋“ฑ(์ตœ๊ณ ์ ): 95=์ฒ ์ˆ˜
๊ผด์ฐŒ(์ตœ์ €์ ): 10=๋งน๊ตฌ
Plaintext

Key ํƒ€์ž…์ด Integer ํƒ€์ž…์ธ๋ฐ Integer๋Š” Comparable<Integer>๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋‹ค.

Set/Map ๊ตฌํ˜„์ฒด ๋น„๊ต ๋ฐ ์„ฑ๋Šฅ (Big-O) – Java8 ์ด์ƒ ๊ธฐ์ค€

๊ตฌํ˜„์ฒด๊ธฐ๋ฐ˜์ž๋ฃŒ๊ตฌ์กฐ์กฐํšŒ์ถ”๊ฐ€์‚ญ์ œํŠน์ง•
HashSet/
HashMap
Hash Table
(+RB Tree)
O(1) ~ O(log n)O(1) ~ O(log n)O(1) ~ O(log n)์ˆœ์„œ๋ณด์žฅ X
๊ฐ€์žฅ ๋น ๋ฆ„
LinkedHashSet/
LinkedHashMap
HashTable
+ LinkedList
O(1) ~ O(log n)O(1) ~ O(log n)O(1) ~ O(log n)์ž…๋ ฅ์ˆœ์„œ(Insert Order) ๋ณด์žฅ
TreeSet/
TreeMap
Red-Black TreeO(log n)O(log n)O(log n)ํ‚ค ๊ธฐ์ค€ ์ •๋ ฌ ์ƒํƒœ ์œ ์ง€

Java 21 Sequenced Collections (์‹œํ€€์Šค ์ปฌ๋ ‰์…˜)

Java 21 (JEP 431)์—์„œ๋Š” ์ปฌ๋ ‰์…˜ ํ”„๋ ˆ์ž„์›Œํฌ์— ๊ฐ€์žฅ ํฐ ๊ตฌ์กฐ์  ๋ณ€ํ™”๊ฐ€ ์ผ์–ด๋‚ฌ๋‹ค. ๋ฐ”๋กœ Sequenced Collections์˜ ๋„์ž…์ด๋‹ค.

์ˆœ์„œ๋Š” ์žˆ๋Š”๋ฐ ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†๋‹ค

์ด์ „๊นŒ์ง€ ์ž๋ฐ”์—๋Š” ์ˆœ์„œ๊ฐ€ ์žˆ๋Š” ์ปฌ๋ ‰์…˜์„ ์•„์šฐ๋ฅด๋Š” ์ƒ์œ„ ํƒ€์ž…์ด ์—†์—ˆ๋‹ค.

  • List: ์ˆœ์„œ ์žˆ์Œ (์ธ๋ฑ์Šค ์ ‘๊ทผ ๊ฐ€๋Šฅ)
  • Deque: ์ˆœ์„œ ์žˆ์Œ (์–‘๋ ์ ‘๊ทผ ๊ฐ€๋Šฅ)
  • LinkedHashSet: ์ˆœ์„œ ์žˆ์Œ (์ž…๋ ฅ ์ˆœ์„œ)

ํ•˜์ง€๋งŒ ์ด๋“ค์˜ ๊ณตํ†ต ์กฐ์ƒ์ธ Collection์ด๋‚˜ Set ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ˆœ์„œ์— ๋Œ€ํ•œ ๊ฐœ๋…์ด ์—†๋‹ค. ๊ทธ๋ž˜์„œ ‘์ฒซ ๋ฒˆ์งธ ์š”์†Œ’๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋‹จ์ˆœํ•œ ์ž‘์—… ์กฐ์ฐจ ๊ตฌํ˜„์ฒด๋งˆ๋‹ค ์ œ๊ฐ๊ฐ์ด์—ˆ๋‹ค.

  • List: list.get(0)
  • Deque: deque.getFirst()
  • LinkedHashSet: iterator().next()

์ƒˆ๋กœ์šด ์ธํ„ฐํŽ˜์ด์Šค ์ฃผ์ž…

Java 21์€ ๊ณ„์ธต ๊ตฌ์กฐ ์‚ฌ์ด์— 3๊ฐœ์˜ ์ƒˆ๋กœ์šด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

  1. SequencedCollection: Collection์„ ์ƒ์† ๋ฐ›์œผ๋ฉฐ List์™€ Deque์˜ ์ƒ์œ„๊ฐ€ ๋œ๋‹ค. addFirst, addLast, getFirst, getLast, removeFirst, removeLast, reversed() ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
  2. SequencedSet: Set ์ด๋ฉด์„œ ์ˆœ์„œ๊ฐ€ ์žˆ๋Š” LinkedHashSet, TreeSet ๋“ฑ์˜ ์ƒ์œ„ ์ธํ„ฐํŽ˜์ด์Šค๋‹ค.
  3. SequencedMap: LinkedHashMap, TreeMap ๋“ฑ์˜ ์ƒ์œ„ ์ธํ„ฐํŽ˜์ด์Šค๋กœ firstEntry, lastEntry, pollFirstEntry, pollLastEntry ๋“ฑ์„ ์ œ๊ณตํ•œ๋‹ค.

์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง

๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์€ reversed() ๋ทฐ์ด๋‹ค. ์ด์ œ List๋‚˜ Set์„ ์—ญ์ˆœ์œผ๋กœ ์ˆœํšŒํ•˜๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด๋‚˜ ์ง๊ด€์ ์œผ๋กœ ๋ณ€ํ–ˆ๋‹ค.
๋‹ค์Œ์€ LinkedHashSet์˜ ๋งˆ์ง€๋ง‰ ์š”์†Œ ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐ ์—ญ์ˆœ ์กฐํšŒ ์ฝ”๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ฐœ์„ ๋˜์—ˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

Java 21 ์ด์ „

LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Cherry");

// ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ์ „์ฒด๋ฅผ ์ˆœํšŒํ•˜๊ฑฐ๋‚˜ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•ด์•ผ ํ–ˆ์Œ
String lastElement = null;
for(String s : set) lastElement = s; // O(n)

// ์—ญ์ˆœ ์ถœ๋ ฅ์„ ์œ„ํ•ด ๋ณ„๋„ ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ ํ•„์š” (๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„)
List<String> list = new ArrayList<>(set);
Collections.reverse(list);
for(String s : list) {
    System.out.println(s);
}
Java

Java 21 ์ดํ›„

// ๋งˆ์ง€๋ง‰ ์š”์†Œ ์ฆ‰์‹œ ์ ‘๊ทผ O(1)
String lastElement = set.getLast(); 

// ์—ญ์ˆœ ๋ทฐ๋ฅผ ํ†ตํ•œ ์ˆœํšŒ (๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ ์—†์Œ)
for(String s : set.reversed()) {
    System.out.println(s);
}
Java

์—ฌ๊ธฐ์„œ reversed()๋Š” ์ƒˆ๋กœ์šด ์ปฌ๋ ‰์…˜์„ ๋ณต์‚ฌํ•ด์„œ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์›๋ณธ ์ปฌ๋ ‰์…˜์„ ๊ฑฐ๊พธ๋กœ ๋ณด์—ฌ์ฃผ๋Š” ๋ทฐ(view)๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ด ๋›ฐ์–ด๋‚˜๋ฉฐ reversed() ๋ทฐ์—์„œ ์š”์†Œ๋ฅผ ์‚ญ์ œํ•˜๋ฉด ์›๋ณธ์—์„œ๋„ ์‚ญ์ œ๋œ๋‹ค.

https://stackoverflow.com/questions/79603303/how-can-i-process-elements-in-reverse-order-across-different-collection-types
https://nipafx.dev/inside-java-newscast-45/

๋ถˆ๋ณ€์„ฑ๊ณผ ์ŠคํŠธ๋ฆผ

Java 9์ดํ›„ ๊ทธ๋ฆฌ๊ณ  Java 16์„ ๊ฑฐ์น˜๋ฉด์„œ ์ปฌ๋ ‰์…˜์„ ์ƒ์„ฑํ•˜๊ณ  ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ์‹์ด ๊ฐ„๊ฒฐํ•˜๊ณ  ์•ˆ์ „ํ•ด์กŒ๋‹ค.

List.of vs Arrays.asList: ๋ถˆ๋ณ€์„ฑ์˜ ์ฐจ์ด

๋ฆฌ์ŠคํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ ์ด ๋‘๊ฐ€์ง€๋ฅผ ์ฃผ๋กœ ํ˜ผ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋“ค์ด ๋งŽ์ด ์žˆ๋Š”๋ฐ ์ด ๋‘˜์€ ๊ฒฐ์ •์ ์ธ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

ํŠน์„ฑArrays.asList(1, 2, 3)List.of(1, 2, 3)
๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ๊ณ ์ • ํฌ๊ธฐ(Fixed-size)
set()์œผ๋กœ ๊ฐ’ ๋ณ€๊ฒฝ์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ add/remove๋Š” ๋ถˆ๊ฐ€
์™„์ „ ๋ถˆ๋ณ€(Immutable).
๊ฐ’ ๋ณ€๊ฒฝ, ์ถ”๊ฐ€, ์‚ญ์ œ ๋ชจ๋“  ์‹œ๋„์‹œ UnsupportedOperationException ๋ฐœ์ƒ
null ํ—ˆ์šฉํ—ˆ์šฉํ•จ.ํ—ˆ์šฉ ์•ˆ ํ•จ. ํฌํ•จ์‹œ NullPointerException ๋ฐœ์ƒ
์ฐธ์กฐ ๊ด€๊ณ„์›๋ณธ ๋ฐฐ์—ด์˜ ๋ทฐ(view)์—ญํ• .
์›๋ณธ ๋ฐฐ์—ด์ด ๋ฐ”๋€Œ๋ฉด ๋ฆฌ์ŠคํŠธ๋„ ๋ฐ”๋€œ
๊ฐ’ ์ž์ฒด๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋…๋ฆฝ์ ์ธ ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ

๊ถŒ์žฅ ์‚ฌํ•ญ: ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ์ฒด(DTO)๋‚˜ ์„ค์ •๊ฐ’์ฒ˜๋Ÿผ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•„์•ผ ํ•  ๋ชฉ๋ก์„ ๋งŒ๋“ค ๋•Œ๋Š” ํ•ญ์ƒ List.of๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜๋„์น˜ ์•Š์€ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

Stream API: Stream.toList() vs Collectors.toList()

Java 8์—์„œ ์ŠคํŠธ๋ฆผ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ๋ชจ์„ ๋•Œ collect(Collector.toList())๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. Java 16๋ถ€ํ„ฐ๋Š” Stream.toList()๊ฐ€ ๋„์ž…๋˜์—ˆ๋‹ค.

// Java 8 ์Šคํƒ€์ผ
List<String> list1 = stream.collect(Collectors.toList());

// Java 16 ์Šคํƒ€์ผ
List<String> list2 = stream.toList();
Java

์ฐจ์ด์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  1. Collectors.toList(): ๋ฐ˜ํ™˜๋˜๋Š” ๋ฆฌ์ŠคํŠธ๊ฐ€ ArrayList๋“ฑ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๋ฆฌ์ŠคํŠธ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค. (๋ช…์„ธ์ƒ ๋ณด์žฅ๋˜์ง€ ์•Š์Œ)
  2. Stream.toList(): ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•œ(Unmodifiable) ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ตœ์ ํ™”๋˜์–ด ์žˆ๊ณ  null ๊ฐ’์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆ˜์ •ํ•  ์ผ์ด ์—†๋‹ค๋ฉด ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์•ˆ์ „ํ•œ Stream.toList()๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

์†Œ์†Œํ•œ ํŒ

contains() ํ•จ์ •

ArrayList.contains()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ค‘๋ณต ์ฒดํฌ๋ฅผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

List<String> list = new ArrayList<>();
//... ๋ฐ์ดํ„ฐ 10๋งŒ ๊ฐœ ์ถ”๊ฐ€...
if (!list.contains("Target")) { // ์—ฌ๊ธฐ์„œ O(n) ๋ฐœ์ƒ!
    list.add("Target");
}
Java

ArrayList์˜ contains๋Š” ๋ฆฌ์ŠคํŠธ ์ „์ฒด๋ฅผ ์ˆœํšŒํ•œ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์„ฑ๋Šฅ์€ ์„ ํ˜•์ ์œผ๋กœ ๋‚˜๋น ์ง„๋‹ค (O(n)). ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ์ด ๋นˆ๋ฒˆํ•˜๋‹ค๋ฉด HashSet์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค. HashSet์˜ contains ์„ฑ๋Šฅ์€ O(1)์ด๋‹ค. ๊ฐ™์€ contains ๋ฉ”์„œ๋“œ๋ผ๊ณ  ํ•˜๋”๋ผ๋„ ๋‚ด๋ถ€ ์ž๋ฃŒ ๊ตฌ์กฐ์— ๋”ฐ๋ผ ์„ฑ๋Šฅ ์ฐจ์ด ๋ฐœ์ƒํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์•ˆ์ „ํ•œ ์‚ญ์ œ

๋ฃจํ”„๋ฅผ ๋Œ๋ฉด์„œ ๋ฆฌ์ŠคํŠธ์˜ ์š”์†Œ๋ฅผ ์‚ญ์ œํ•˜๋Š” ์ฝ”๋“œ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋งŽ์ด ์‹ค์ˆ˜ํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค. for-each ๋ฃจํ”„์—์„œ list.remove()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ConcurrentModificationException์ด ๋ฐœ์ƒํ•œ๋‹ค.

for (String s : list) {
    if (s.startsWith("A")) {
        list.remove(s); // ConcurrentModificationException ์˜ˆ์™ธ ๋ฐœ์ƒ!
    }
}
Java

iterator๊ฐ€ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆœํšŒํ•˜๋Š” ๋„์ค‘์— ๋ฆฌ์ŠคํŠธ์˜ ๋‚ด์šฉ์ด(๊ตฌ์กฐ) ๋ณ€๊ฒฝ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. (for-each๋Š” iterator๋™์ž‘)
java 8์ด์ „์˜ ๊ฒฝ์šฐ์—๋Š” iterator์˜ remove()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์‚ญ์ œํ•ด์•ผ ํ•œ๋‹ค.

Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String s = iter.next();
    if (s.startsWith("A")) {
        iter.remove(); // ์•ˆ์ „ํ•จ: Iterator๊ฐ€ ์‚ญ์ œํ•˜๊ณ  ์Šค์Šค๋กœ ์ƒํƒœ ์—…๋ฐ์ดํŠธํ•จ
    }
}
Java

java 8๋ถ€ํ„ฐ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์ตœ์ ํ™”๋œ removeIf ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

list.removeIf(s -> s.startsWith("A"));
Java

removeIf๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ iterator๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ˆ์ „ํ•˜๊ฒŒ ์‚ญ์ œํ•˜๊ณ  ArrayList์˜ ๊ฒฝ์šฐ ์‚ญ์ œ ํ›„ ๋ฐฐ์—ด ๋ณต์‚ฌ ํšŸ์ˆ˜๋ฅผ ์ตœ์†Œํ™” ํ•˜๋„๋ก ์ตœ์ ํ™” ๋˜์–ด ์žˆ์–ด ์„ฑ๋Šฅ์ ์œผ๋กœ๋„ ์œ ๋ฆฌํ•˜๋‹ค.


์ง€๊ธˆ๊นŒ์ง€ Java Collection Frameworkd์—์„œ ๋ฟŒ๋ฆฌ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š” List, Map, Set์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•ด๋ณด์•˜๋‹ค. Collection์€ ๋‹จ์ˆœํžˆ ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ๋ฅผ ๋„˜์–ด ๊ทธ ํŠน์„ฑ์— ๋งž๊ฒŒ ๋‚ด๋ถ€ ์ž๋ฃŒ ๊ตฌ์กฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋˜์–ด ์žˆ๊ณ  ๋™์ž‘ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•œ ๊ฒƒ ๊ฐ™๋‹ค. ๊ทผ๋ฐ ๋งค๋ฒˆ ๋ณผ ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๋А๋‚Œ์€ ์™œ์ผ๊นŒ? ใ… ใ…  ๋ณผ ๋•Œ๋Š” ์ดํ•ด๊ฐ€ ๋˜๋Š”๋ฐ ์ง€๋‚˜๊ณ ๋‚˜๋ฉด ๊ธˆ๋ฐฉ ์žŠ์–ด๋ฒ„๋ฆฐ๋‹ค. ์ž์ฃผ ๋“ค์—ฌ๋‹ค๋ด์•ผ๊ฒ ๋‹ค.

์ฐธ๊ณ ํ•˜๋ฉด ์ข‹์€ ์š”์•ฝ

  1. ์ผ๋ฐ˜์ ์ธ ์ƒํ™ฉ์—์„œ๋Š” ArrayList๊ฐ€ LinkedList ๋ณด๋‹ค ๋น ๋ฅด๋‹ค. (CPU Cache locality)
  2. ์ค‘๋ณต ์ œ๊ฑฐ์™€ ๋น ๋ฅธ ๊ฒ€์ƒ‰์ด ํ•„์š”ํ•  ๋• ์ฃผ์ €์—†์ด HashSet์„ ์‚ฌ์šฉํ•˜์ž.
  3. Java 21์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด SequencedCollection์˜ reversed(), getLast()๋“ฑ์„ ์ ๊ทน ํ™œ์šฉํ•˜์ž.
  4. ๋ถˆ๋ณ€ ๋ฆฌ์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•  ๋• List.of()์™€ Stream.toList()๋ฅผ ์‚ฌ์šฉํ•˜์ž.