1. 컬렉션에서 요소 검색
표준 메서드로 검색하기
예를 들어 이름 목록 같은 리스트가 있을 때:
List<String> names = List.of("Anna", "Boris", "Viktoriya", "Anna", "Dmitriy");
Java는 검색을 위한 편리한 메서드를 제공합니다:
- contains(Object o) — 컬렉션에 원소가 존재하는지 확인합니다.
- indexOf(Object o) — 요소가 처음 나타나는 인덱스를 반환합니다(없으면 -1).
- lastIndexOf(Object o) — 요소가 마지막으로 나타나는 인덱스를 반환합니다(없으면 -1).
예시:
System.out.println(names.contains("Anna")); // true
System.out.println(names.indexOf("Anna")); // 0
System.out.println(names.lastIndexOf("Anna")); // 3
System.out.println(names.contains("Sergey")); // false
사실: Set 타입 컬렉션에는 indexOf와 lastIndexOf가 없습니다 — Set에는 애초에 인덱스가 없고, 고유 값만 있습니다.
조건으로 검색하기
가끔은 특정 값이 아니라 어떤 조건을 만족하는 요소를 찾아야 합니다. 예를 들어 길이가 6자를 초과하는 첫 번째 이름을 찾는 경우. 일반적인 for 루프가 아주 잘 맞습니다. 적합한 요소를 찾는 즉시 break를 사용하세요.
List<String> names = List.of("Anna", "Boris", "Viktoriya", "Anna", "Dmitriy");
String found = null;
for (String name : names) {
if (name.length() > 6) {
found = name;
break; // 첫 번째로 조건을 만족하는 값을 찾았으니 루프 종료
}
}
System.out.println(found); // Viktoriya
최대값과 최소값 찾기
비교 가능한 요소(예: 숫자)로 이루어진 컬렉션에서는 Collections 클래스를 사용해 최대값과 최소값을 빠르게 찾을 수 있습니다.
List<Integer> numbers = List.of(10, 5, 20, 7, 20, 3);
int max = Collections.max(numbers); // 20
int min = Collections.min(numbers); // 3
System.out.println("최댓값: " + max);
System.out.println("최솟값: " + min);
중요: 요소는 비교 가능해야 합니다(Comparable을 구현). 그렇지 않으면 Comparator를 전달해야 합니다.
2. 컬렉션 정렬
기본 정렬
정렬은 변경 가능한 리스트(예: ArrayList, LinkedList)에서만 가능합니다. Set과 Map 타입 컬렉션은 직접적인 정렬을 지원하지 않습니다.
기본적으로 정렬은 “자연 순서”로 진행됩니다. 숫자는 오름차순, 문자열은 알파벳 순입니다.
List<Integer> numbers = new ArrayList<>(List.of(5, 1, 7, 3));
Collections.sort(numbers);
System.out.println(numbers); // [1, 3, 5, 7]
리스트의 sort 메서드로도 같은 작업을 할 수 있습니다:
List<Integer> numbers = new ArrayList<>(List.of(5, 1, 7, 3));
numbers.sort(null); // null은 '자연 순서'를 사용하라는 뜻
System.out.println(numbers); // [1, 3, 5, 7]
Comparator로 정렬
사용자 정의 규칙이 필요하다면 — 예를 들어 문자열을 길이 기준으로 정렬:
List<String> words = new ArrayList<>(List.of("kot", "slon", "mukha", "nosorog"));
words.sort(Comparator.comparingInt(String::length));
System.out.println(words); // [kot, mukha, slon, nosorog]
내림차순으로:
words.sort(Comparator.comparingInt(String::length).reversed());
System.out.println(words); // [nosorog, slon, mukha, kot]
예전 스타일 — Collections.sort 사용:
Collections.sort(words, Comparator.comparingInt(String::length));
3. 컬렉션별 정렬 특성
정렬은 리스트에만 적용
정렬 메서드(sort, Collections.sort)는 요소의 순서를 유지하는 컬렉션(예: List)에만 동작합니다. Set과 Map에는 이러한 메서드가 없습니다.
Set을 정렬하려는 시도:
Set<Integer> mySet = new HashSet<>(List.of(3, 1, 2));
Collections.sort(mySet); // 컴파일 오류: sort는 List를 요구합니다!
Set에서 정렬된 리스트가 필요하다면:
List<Integer> sortedFromSet = new ArrayList<>(mySet);
Collections.sort(sortedFromSet);
System.out.println(sortedFromSet); // [1, 2, 3]
Map 정렬: 키와 값 기준
Map을 직접 정렬할 수는 없지만, 다음처럼 할 수 있습니다:
- “키-값” 쌍 리스트를 얻는다
- 원하는 기준으로 그 리스트를 정렬한다
- 필요하다면 새로운 Map을 만든다
예: 값 기준 정렬
Map<String, Integer> scores = Map.of(
"Anna", 15,
"Boris", 20,
"Vika", 12
);
List<Map.Entry<String, Integer>> entries = new ArrayList<>(scores.entrySet());
entries.sort(Map.Entry.comparingByValue());
for (Map.Entry<String, Integer> entry : entries) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// Vika: 12
// Anna: 15
// Boris: 20
객체를 필드 기준으로 정렬
사용자 클래스를 하나 가정해 봅시다:
class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
그리고 사용자 리스트:
List<User> users = new ArrayList<>(List.of(
new User("Anna", 22),
new User("Boris", 18),
new User("Vika", 25)
));
나이 기준 정렬:
users.sort(Comparator.comparingInt(u -> u.age));
System.out.println(users); // [Boris (18), Anna (22), Vika (25)]
내림차순:
users.sort(Comparator.comparingInt((User u) -> u.age).reversed());
System.out.println(users); // [Vika (25), Anna (22), Boris (18)]
4. 컬렉션 검색/정렬 시 자주 하는 실수
오류 №1: 불변 리스트를 정렬하려 함. List.of(...)로 생성한 리스트는 변경할 수 없습니다 — sort를 호출하면 UnsupportedOperationException이 발생합니다.
List<Integer> immutable = List.of(3, 1, 2);
immutable.sort(null); // 예외를 던집니다!
오류 №2: Set 또는 Map을 직접 정렬하려 함. 정렬 메서드는 Set과 Map에는 동작하지 않습니다. 정렬이 필요하면 먼저 데이터를 리스트로 변환하세요.
오류 №3: 잘못된 객체 비교. 비교 시 정수를 그대로 빼지 마세요 — 오버플로가 발생할 수 있습니다. u1.age - u2.age 대신 Integer.compare 또는 Comparator.comparingInt을 사용하세요.
// users.sort((u1, u2) -> u1.age - u2.age); // 작동은 하지만 오버플로 위험이 있습니다!
오류 №4: 복잡한 검색에 contains 사용. contains는 equals를 기준으로 한 완전 일치만 확인합니다. 문자열의 일부나 객체의 특정 필드로 검색하려면 조건 검사를 포함한 루프 또는 Comparator/스트림을 사용하세요.
GO TO FULL VERSION