0Pricing
Java Academy · 강의

부분 맵과 범위 뷰

정렬된 맵에서 범위 기반 조회를 위해 subMap, headMap, tailMap 뷰를 추출합니다.

부분 맵과 범위 뷰은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

TreeMap의 범위 뷰

TreeMap의 subMap, headMap, tailMap은 원본을 기반으로 하는 뷰를 반환합니다. 이러한 뷰는 기본 맵의 변경 사항과 그 반대 방향의 변경 사항도 반영합니다. 뷰를 통한 변경 사항은 원본에도 반영됩니다.

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 1; i <= 10; i++) map.put(i * 10, "item" + i);

var view = map.subMap(30, 70); // [30, 70)
System.out.println(view); // {30=item3, 40=item4, 50=item5, 60=item6}

map.put(45, "new"); // also visible through view!
System.out.println(view.containsKey(45)); // true

headMap: 경계보다 작은 키

headMap(toKey)는 키가 toKey보다 엄격히 작은 모든 Entry를 반환합니다. 경계값을 포함하려면 포함 변형인 headMap(toKey, true)를 사용합니다.

TreeMap<String, Integer> words = new TreeMap<>();
"banana cherry apple date elderberry".chars()
    .mapToObj(c -> String.valueOf((char)c)).distinct()
    .forEach(w -> words.put(w, w.length()));
// Actually let's use real words:
TreeMap<String, Integer> wc = new TreeMap<>();
wc.put("apple",5); wc.put("banana",6); wc.put("cherry",6); wc.put("date",4);

System.out.println(wc.headMap("cherry")); // {apple=5, banana=6}

tailMap: 경계부터 시작하는 키

tailMap(fromKey)는 키가 fromKey 이상인 모든 Entry를 반환합니다.

TreeMap<Integer, String> grades = new TreeMap<>();
grades.put(50,"F"); grades.put(60,"D"); grades.put(70,"C"); grades.put(80,"B"); grades.put(90,"A");

// All passing grades (>= 60)
var passing = grades.tailMap(60);
System.out.println(passing); // {60=D, 70=C, 80=B, 90=A}

포함 경계를 사용하는 subMap

4개 인수를 받는 subMap(from, fromInclusive, to, toInclusive)는 경계 포함 여부를 완전히 제어할 수 있게 합니다.

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 10; i <= 100; i += 10) map.put(i, "v"+i);

// [30, 60] — both inclusive
System.out.println(map.subMap(30, true, 60, true));
// {30=v30, 40=v40, 50=v50, 60=v60}

// (30, 60) — both exclusive
System.out.println(map.subMap(30, false, 60, false));
// {40=v40, 50=v50}

뷰를 통한 수정

subMap 뷰에서 수행한 Put/remove 연산은 원본 맵에 반영되며 그 반대도 마찬가지입니다. 뷰의 범위 밖에 있는 키를 삽입하려고 하면 예외가 발생합니다.

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 1; i <= 5; i++) map.put(i * 10, "v" + i);

var view = map.subMap(20, 40); // [20, 40)
view.remove(20); // removes from both view and original map
System.out.println(map.containsKey(20)); // false

// This would throw IllegalArgumentException:
// view.put(50, "out of range");

사용 사례: 로그 범위 조회

TreeMap의 범위 뷰를 사용하여 두 타임스탬프 사이의 모든 로그 항목을 가져옵니다.

import java.time.*;
TreeMap<LocalDateTime, String> logs = new TreeMap<>();
logs.put(LocalDateTime.of(2024,1,1,8,0), "Server start");
logs.put(LocalDateTime.of(2024,1,1,10,0), "Request spike");
logs.put(LocalDateTime.of(2024,1,1,14,0), "Maintenance");
logs.put(LocalDateTime.of(2024,1,1,18,0), "Server stop");

var morning = logs.subMap(
    LocalDateTime.of(2024,1,1,8,0), true,
    LocalDateTime.of(2024,1,1,12,0), false
);
morning.forEach((t,m) -> System.out.println(t+" : "+m));

사용 사례: 가격 범위 조회

TreeMap의 키로 가격을 사용하여 가격 범위에 해당하는 모든 Product를 찾습니다.

TreeMap<Double, String> products = new TreeMap<>();
products.put(9.99, "Pen");
products.put(24.99, "Book");
products.put(49.99, "Headphones");
products.put(299.99, "Tablet");

double min = 10.0, max = 100.0;
var affordable = products.subMap(min, true, max, true);
affordable.forEach((p,n) -> System.out.println(n+" $"+p));
// Book $24.99, Headphones $49.99

내림차순 subMap

뷰에 descendingMap()을 연결하여 역순으로 탐색합니다.

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 10; i <= 100; i += 10) map.put(i, "v"+i);

// Get [40, 80] in descending order
map.subMap(40, true, 80, true)
   .descendingMap()
   .forEach((k,v) -> System.out.println(k + "=" + v));
// 80=v80, 70=v70, 60=v60, 50=v50, 40=v40

NavigableMap 인터페이스

NavigableMap은 SortedMap을 확장하고 ceiling/floor/higher/lower 키 탐색과 내림차순 뷰를 추가합니다. TreeMap이 가장 일반적인 구현이며, ConcurrentSkipListMap은 스레드 안전한 대안입니다.

뷰의 성능

하위 맵 뷰의 연산(get, put, containsKey)은 기본 TreeMap과 동일한 O(log n)입니다. 뷰 자체를 만드는 데는 O(1)이 걸리며 복사는 발생하지 않습니다. 뷰에서 n개의 키를 범위 스캔하는 데는 O(log N + n)이 걸립니다. 여기서 N은 전체 맵의 크기입니다.

주의할 점: 오래된 뷰

뷰는 원본 맵을 기반으로 하므로 원본 맵이 비워지면 뷰가 비어 있거나 예외를 발생시킬 수 있습니다. 뷰가 실시간으로 반영되며 의도한 수명 주기를 넘어 보관해서는 안 된다는 점을 항상 문서화하십시오.

TreeMap<Integer, String> map = new TreeMap<>();
map.put(10, "a"); map.put(20, "b"); map.put(30, "c");

var view = map.subMap(10, 30);
map.clear(); // view becomes empty
System.out.println(view.size()); // 0 — but no exception

빠른 확인

키가 {10,20,30,40,50,60,70,80}인 TreeMap에서 map.subMap(30, false, 70, true)를 호출합니다. 결과에는 어떤 키가 포함되나요?

복습: 하위 맵과 범위 뷰

핵심 내용:

  • subMap, headMap, tailMap은 실시간으로 반영되는 원본 기반 뷰를 반환하며 복사하지 않습니다
  • 뷰의 변경 사항은 원본 맵에 반영되고 그 반대도 마찬가지입니다
  • 경계를 완전히 제어하려면 4개 인수의 subMap(from, fromInclusive, to, toInclusive)을 사용합니다
  • 뷰를 통해 범위 밖의 키를 put하면 IllegalArgumentException이 발생합니다
  • 범위 스캔의 복잡도는 O(log N + n)입니다

자주 묻는 질문

“부분 맵과 범위 뷰” 강의는 무료인가요?

네 — “부분 맵과 범위 뷰” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“부분 맵과 범위 뷰”에서 뭘 배우나요?

정렬된 맵에서 범위 기반 조회를 위해 subMap, headMap, tailMap 뷰를 추출합니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Java Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“부분 맵과 범위 뷰” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. TreeMap: 정렬된 키-값 쌍
  2. 부분 맵과 범위 뷰
  3. TreeSet과 NavigableSet
  4. 트리 컬렉션의 사용자 정의 순서
← Java Academy(으)로 돌아가기