0Pricing
Java Academy · 강의

트리 컬렉션의 사용자 정의 순서

Comparator를 TreeMap과 TreeSet에 제공해 도메인에 맞는 정렬 순서를 정의합니다.

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

사용자 정의 순서가 필요한 이유

트리 컬렉션(TreeMap, TreeSet)은 기본적으로 자연 순서를 사용합니다. 도메인 객체에 자연 순서가 없거나 다른 정렬이 필요할 때는 생성 시 Comparator를 제공합니다.

TreeMap 생성 시 Comparator 지정

사용자 정의 규칙에 따라 키를 정렬하려면 comparator를 전달합니다. 예를 들어 알파벳 역순으로 정렬할 수 있습니다.

import java.util.*;

TreeMap<String, Integer> map = new TreeMap<>(Comparator.reverseOrder());
map.put("banana", 2);
map.put("apple", 1);
map.put("cherry", 3);

map.forEach((k,v) -> System.out.println(k)); // cherry, banana, apple

TreeSet 생성 시 Comparator 지정

요소의 자연 순서와 관계없이 정렬 순서를 제어하려면 TreeSet에 comparator를 제공합니다.

TreeSet<String> byLength = new TreeSet<>(
    Comparator.comparingInt(String::length)
              .thenComparing(Comparator.naturalOrder())
);
byLength.addAll(List.of("fig","apple","kiwi","date","banana"));

for (String s : byLength) System.out.print(s + " ");
// fig date kiwi apple banana

여러 필드로 객체 정렬하기

주요 필드로 정렬한 다음 동률을 해소하기 위해 보조 필드로 정렬하도록 comparator를 연결할 수 있습니다.

record Employee(String name, String dept, int salary) {}

TreeSet<Employee> sorted = new TreeSet<>(
    Comparator.comparing(Employee::dept)
              .thenComparingInt(Employee::salary).reversed()
              .thenComparing(Employee::name)
);
sorted.add(new Employee("Alice", "Eng", 90_000));
sorted.add(new Employee("Bob",   "Eng", 85_000));
sorted.add(new Employee("Carol", "HR",  70_000));

for (Employee e : sorted) System.out.println(e.dept()+" "+e.name());

equals와의 일관성

중요한 규칙: TreeSet/TreeMap에서 사용하는 comparator가 컬렉션의 동등성을 정의합니다. comparator.compare(a, b) == 0이면 a.equals(b)가 false인 경우에도 a와 b를 같은 키로 간주합니다.

// Comparator ignoring case — "apple" and "APPLE" become the same key!
TreeSet<String> ci = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
ci.add("apple");
ci.add("APPLE"); // not added — same by comparator
System.out.println(ci.size()); // 1

대소문자를 구분하지 않는 TreeMap

실무에서 자주 필요한 형태는 키가 대소문자를 구분하지 않는 문자열인 TreeMap입니다(HTTP 헤더와 설정 키에 유용합니다).

TreeMap<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
headers.put("Content-Type", "application/json");
headers.put("content-type", "text/html"); // overwrites!

System.out.println(headers.get("CONTENT-TYPE")); // text/html
System.out.println(headers.size()); // 1

Null 안전 Comparator

자연 순서를 사용하는 트리 컬렉션은 null 키에 대해 NPE를 발생시킵니다. null을 최솟값 키로 허용하려면 null을 안전하게 처리하는 comparator를 사용합니다.

TreeMap<String, Integer> map = new TreeMap<>(
    Comparator.nullsFirst(Comparator.naturalOrder())
);
map.put(null, 0);
map.put("b", 2);
map.put("a", 1);

map.forEach((k,v) -> System.out.println(k + "=" + v));
// null=0, a=1, b=2

도메인 객체 예시: 가격순 Product

TreeSet에서 Product를 가격순으로 정렬하고, 고유성을 유지하기 위한 동률 해소 기준으로 이름을 사용합니다.

record Product(String name, double price) {}

TreeSet<Product> catalog = new TreeSet<>(
    Comparator.comparingDouble(Product::price)
              .thenComparing(Product::name)
);
catalog.add(new Product("Widget", 9.99));
catalog.add(new Product("Gadget", 24.99));
catalog.add(new Product("Donut",  9.99));

catalog.forEach(p -> System.out.println(p.name() + " $" + p.price()));
// Donut $9.99, Widget $9.99, Gadget $24.99

Comparator 가져오기

TreeMap/TreeSet에서 comparator()를 호출하면 사용자 정의 comparator를 가져올 수 있습니다. 자연 순서를 사용하는 경우에는 null을 반환합니다.

TreeMap<String, Integer> map = new TreeMap<>(Comparator.reverseOrder());
System.out.println(map.comparator() != null); // true

TreeMap<String, Integer> natural = new TreeMap<>();
System.out.println(natural.comparator());      // null

Comparator 조합

Java의 Comparator는 깔끔한 조합을 위한 연결 가능한 팩토리 메서드를 제공합니다.

Comparator<String> comp =
    Comparator.comparingInt(String::length)   // by length
              .thenComparing(Comparator.naturalOrder()); // then alphabetically

TreeSet<String> ts = new TreeSet<>(comp);
ts.addAll(List.of("go", "java", "c", "rust", "py"));
ts.forEach(s -> System.out.print(s + " "));
// c go py java rust

사용자 정의 Comparator를 사용하지 말아야 할 때

TreeMap 키나 TreeSet 요소에 대해 equals와 일관되지 않는 comparator는 사용하지 마십시오. 이러한 comparator는 혼란스러운 누락 항목을 만듭니다. 모든 컬렉션 상황에서 올바르게 동작하도록 compare(a, b) == 0인 경우와 a.equals(b)인 경우가 서로 같도록 하십시오.

빠른 확인

TreeSet이 String::length만을 기준으로 하는 comparator를 사용합니다. "cat"과 "dog"을 모두 add하면 어떻게 되나요?

복습: 사용자 지정 정렬

핵심 내용:

  • TreeMap/TreeSet 생성자에 Comparator를 전달하여 사용자 지정 정렬을 정의합니다
  • Comparator가 정의하는 동등성이 트리 컬렉션의 고유성을 결정합니다
  • 예상하지 못한 결과를 피하려면 Comparator가 equals와 일관되도록 해야 합니다
  • null을 안전하게 처리하는 정렬에는 Comparator.nullsFirst/nullsLast를 사용합니다
  • 여러 필드를 정렬하려면 thenComparing으로 연결합니다

자주 묻는 질문

“트리 컬렉션의 사용자 정의 순서” 강의는 무료인가요?

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

“트리 컬렉션의 사용자 정의 순서”에서 뭘 배우나요?

Comparator를 TreeMap과 TreeSet에 제공해 도메인에 맞는 정렬 순서를 정의합니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

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

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

“트리 컬렉션의 사용자 정의 순서” 강의는 얼마나 걸리나요?

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

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

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

이 강의의 모든 강의

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