Post

[Coding Test] 유용한 JAVA 문법

Collections

Collection vs Collections

  • Collection : 인터페이스. List, Set, Map부모
  • Collections: 클래스. 컬렉션을 다루는 도구


Collections 란? (java.util.Collections)

  • List, Set, Map 과 같은 컬렉션에 저장된 데이터를 다룰 때 사용하는 유틸리티 클래스.
  • Collection 클래스를 이용하면 정렬하기, 최댓값 찾기, 특정 값으로 채우기 등 다양한 작업을 쉽게 수행할 수 있다.


1. 정렬과 순서 제어 (Sorting & Ordering)


sort() - 리스트 정렬

  • Collections.sort(List<T> list)
    • 리스트를 오름차순으로 정렬한다.
    • 리스트의 요소가 Comparable 인터페이스를 구현하고 있어야 한다.
    • (Integer, String 등은 이미 구현되어 있음)
  • Collections.sort(List<T> list, Comparator<? super T> c)
    • 직접 만든 Comparator의 규칙에 따라 리스트를 정렬한다.
    • 내림차순이나 복잡한 기준으로 정렬할 때 사용한다.


    reverseOrder() : 내림차순 ‘규칙’ 제공
    reverse()와 이름이 비슷하지만, reverseOrder()는 행동이 아니라 ‘내림차순’이라는 정렬 규칙(Comparator)을 만들어 반환한다.
    Java 8부터는 List.sort()와 Comparator.reverseOrder()를 사용하는 것이 더 권장된다.


1
2
3
4
5
6
7
8
9
List<Integer> numbers = new ArrayList<>(Arrays.asList(4, 1, 5, 2, 3));

// 오름차순 정렬
Collections.sort(numbers);
// numbers -> [1, 2, 3, 4, 5]

// 내림차순 정렬 (Comparator 사용)
Collections.sort(numbers, Collections.reverseOrder());
// numbers -> [5, 4, 3, 2, 1]


reverse() - 순서 뒤집기

1
2
3
List<Integer> list = new ArrayList<>(Arrays.asList(1, 4, 2, 5));
Collections.reverse(list);
// list -> [5, 2, 4, 1] (정렬이 아니라 순서만 뒤집힘)


shuffle() - 무작위로 섞기

1
2
Collections.shuffle(list);
// list -> [4, 1, 5, 2] (실행할 때마다 결과가 바뀜)


2. 검색과 탐색 (Searching & Finding)


binarySearch() - 이진 탐색

  • 반드시 정렬된 리스트에서 특정 값의 인덱스를 찾는다.
  • 정렬되지 않은 리스트에서 사용하면 잘못된 결과를 반환한다.
1
2
List<Integer> sortedList = Arrays.asList(10, 20, 30, 40, 50);
int index = Collections.binarySearch(sortedList, 30); // index -> 2


max() / min() - 최댓값 / 최솟값 찾기

  • 컬렉션 전체에서 가장 크거나 작은 요소를 찾아 반환한다.
1
2
int maxValue = Collections.max(sortedList); // 50
int minValue = Collections.min(sortedList); // 10


frequency() - 빈도수 계산

  • 컬렉션에서 특정 요소가 몇 번 등장하는지 계산한다.
1
2
List<String> fruits = Arrays.asList("apple", "banana", "apple", "orange");
int count = Collections.frequency(fruits, "apple"); // count -> 2


3. 데이터 조작


replaceAll() - 값 교체

  • 리스트 내의 특정 값을 찾아 다른 값으로 모두 교체한다.
1
2
Collections.replaceAll(fruits, "apple", "grape");
// fruits -> ["grape", "banana", "grape", "orange"]




람다(Lambda)와 스트림(Stream) API


람다와 스트림이란?

  • 람다(Lambda) : 이름 없는 함수(Anonymous Function). 메서드의 인자로 ‘코드(동작)’를 전달할 수 있게 해주는 문법.

  • 스트림(Stream) : 데이터의 흐름. 컬렉션 데이터를 파이프라인처럼 여러 단계로 가공하고 처리하는 기능.

  • ‘어떻게(HOW)’가 아닌 ‘무엇을(WHAT)’에 집중하는 선언적 프로그래밍을 통해 코드를 매우 간결하고 가독성 높게 만들어준다.


1. 람다 표현식 (Lambda Expression)

  • 기존의 익명 내부 클래스 방식을 획기적으로 줄여주는 문법.

  • 하나의 추상 메서드만 가진 인터페이스(함수형 인터페이스)를 구현할 때 사용.


Comparator 구현 예시

1
2
3
4
5
6
7
8
9
10
11
12
// Before (익명 클래스)

list.sort(new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o1.length() - o2.length();
    }
});

// After (람다 표현식)

list.sort((s1, s2) -> s1.length() - s2.length());


2. 스트림 API (Stream API)

  • 스트림은 생성 → 중간 연산 → 최종 연산 3단계의 파이프라인으로 동작한다.

  • 중간 연산은 여러 개를 연결할 수 있으며, 최종 연산이 호출될 때 한 번에 처리된다 (지연 연산).


코딩 테스트 필수 중간 연산

  • filter(조건): 조건에 맞는 데이터만 남긴다.

  • map(함수): 각 데이터를 특정 형태로 변환한다.

  • sorted(): 데이터를 오름차순으로 정렬한다. (sorted(Comparator)로 기준 지정 가능)

  • distinct(): 중복된 데이터를 제거한다.


코딩 테스트 필수 최종 연산

  • collect(Collectors.toList()) : 스트림의 요소들을 모아 List로 만든다.

  • forEach(동작) : 각 요소에 대해 특정 동작을 수행한다. (주로 출력 시 사용)

  • count() : 요소의 개수를 센다.

  • reduce(초기값, 연산) : 모든 요소를 하나로 합치는 연산을 수행한다. (예: 합계 구하기)

  • anyMatch() / allMatch() / noneMatch() : 특정 조건을 만족하는 요소가 있는지(하나라도/모두/전혀 없는지) 확인한다.


3. 예제


예제 1: 백준 11286번 (절댓값 힙)

1
2
3
4
5
6
7
8
9
10
11
12
// 문제: 배열에서 절댓값이 가장 작은 값을 출력하기. 절댓값이 가장 작은 값이 여러개일 때는, 가장 작은 수를 출력하기.

PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> {
  int first_abs = Math.abs(a);
  int second_abs = Math.abs(b)

  if(first_abs == second_abs){  // 절댓값이 같은 경우에는 내림차순
    return a - b;
  }
  
  return first_abs - second_abs;  // 절댓값이 다른 경우에는 작은 값 리턴
});


예제 2: 숫자 배열 가공

1
2
3
4
5
6
7
8
9
10
11
12
// 문제: 정수 배열에서 0보다 큰 수만 골라, 각 숫자를 제곱한 뒤, 내림차순으로 정렬하여 새로운 리스트 만들기

int[] arr = {1, -2, 3, -5, 4, 0};

List<Integer> result = Arrays.stream(arr)       // 1. 배열로 스트림 생성
                             .filter(n -> n > 0)    // 2. 양수만 필터링 [1, 3, 4]
                             .map(n -> n * n)     // 3. 각자 제곱 [1, 9, 16]
                             .sorted(Comparator.reverseOrder()) // 4. 내림차순 정렬 [16, 9, 1]
                             .boxed()             // 5. IntStream을 Stream<Integer>로 변환
                             .collect(Collectors.toList()); // 6. List로 수집

// result -> [16, 9, 1]


예제 3: 문자열 리스트 처리

1
2
3
4
5
6
7
8
9
10
// 문제: 파일 이름 리스트에서 "java" 확장자만 골라, 파일명 길이순으로 정렬하기

List<String> fileNames = Arrays.asList("solution.java", "test.cpp", "README.md", "main.java");

List<String> javaFiles = fileNames.stream()
                                  .filter(name -> name.endsWith(".java"))
                                  .sorted(Comparator.comparingInt(String::length))
                                  .collect(Collectors.toList());

// javaFiles -> ["main.java", "solution.java"]




정규 표현식 (Regular Expressions)

정규 표현식이란?

  • 문자열에서 특정 패턴을 검색, 대체, 추출하기 위해 사용되는 ‘패턴 매칭 언어’.

  • 복잡한 규칙을 가진 문자열을 다룰 때, 코드를 매우 간결하게 만들어주는 강력한 도구.

  • 코딩 테스트에서는 주로 문자열 파싱, 유효성 검사, 특정 패턴 추출 등에 활용된다.


자주 사용하는 정규 표현식 문법

종류문법설명
문자.임의의 한 문자 (줄바꿈 문자 제외)
 \d숫자 (0-9)
 \D숫자가 아닌 문자
 \w알파벳, 숫자, 언더스코어(_) 중 하나
 \W\w가 아닌 문자 (특수 문자 등)
 \s공백 문자 (스페이스, 탭, 줄바꿈 등)
 \S공백 문자가 아닌 문자
경계^문자열의 시작
 $문자열의 끝
 \b단어의 경계
그룹[...]대괄호 안의 문자 중 하나 (예: [abc]는 a, b, c 중 하나)
 [^...]대괄호 안의 문자를 제외한 나머지 문자 (예: [^0-9]는 숫자가 아님)
 (...)그룹화. 패턴을 하나의 단위로 묶음
 A\|BA 또는 B
수량자*0번 이상 반복
 +1번 이상 반복
 ?0번 또는 1번 등장
 {n}정확히 n번 반복
 {n,}n번 이상 반복
 {n,m}n번 이상, m번 이하 반복


Java에서 정규 표현식 사용하기


1. String.matches()

  • 문자열 전체가 주어진 정규 표현식과 완전히 일치하는지 검사한다.
  • boolean 값을 반환하여 유효성 검사에 주로 사용된다.


1
2
3
4
String email = "test@example.com";
String emailRegex = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$";

boolean isValid = email.matches(emailRegex); // true


2. String.replaceAll() / String.split()

  • replaceAll(regex, replacement): 문자열에서 정규 표현식에 맞는 모든 부분을 찾아 다른 문자열로 교체한다.
  • split(regex): 정규 표현식을 기준으로 문자열을 분리하여 문자열 배열로 반환한다.


1
2
3
4
5
6
7
8
9
10
String text = "전화번호는 010-1234-5678 입니다. 집은 02-987-6543 입니다.";

// 숫자만 추출하기 (숫자가 아닌 모든 문자를 ""으로 교체)
String numbers = text.replaceAll("[^0-9]", ""); 
// numbers -> "01012345678029876543"

// 공백, 쉼표, 하이픈을 기준으로 문자열 분리
String data = "사과,바나나-딸기 포도";
String[] fruits = data.split("[,\\s-]"); // 쉼표, 공백, 하이픈 중 하나를 기준으로 분리
// fruits -> ["사과", "바나나", "딸기", "포도"]


3. PatternMatcher 클래스

  • 더 복잡하고 세밀한 정규 표현식 처리가 필요할 때 사용되는 정석적인 방법.
  • Pattern: 정규 표현식 패턴을 컴파일하여 객체로 만듦.
  • Matcher: Pattern 객체를 이용해 실제 문자열과 매칭 작업을 수행.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String source = "ID: user1, ID: user2, ID: user3";
String regex = "ID: (\\w+)"; // ID: 뒤의 단어(알파벳/숫자)를 그룹으로 캡처

Pattern pattern = Pattern.compile(regex); // 1. 패턴 컴파일
Matcher matcher = pattern.matcher(source);  // 2. 매처 생성

// matcher.find() : 패턴과 일치하는 다음 부분을 찾음
while (matcher.find()) {
    // matcher.group(0) : 매칭된 전체 문자열 (e.g., "ID: user1")
    // matcher.group(1) : 첫 번째 그룹에 매칭된 문자열 (e.g., "user1")
    System.out.println(matcher.group(1)); 
}
// 출력:
// user1
// user2
// user3


This post is licensed under CC BY 4.0 by the author.