Blog

Java Stream: 람다식과 메서드 참조로 목록 처리하기

Java 8의 Stream을 공부하면서 람다식과 메서드 참조를 함께 정리했습니다. 목록을 출력하고 조건에 맞는 값만 남긴 뒤 문자열을 숫자로 바꾸는 예제입니다.

비교자를 람다식으로 바꾸기

먼저 정렬 기준을 익명 클래스로 작성했습니다. 두 번째 값이 같으면 첫 번째 값으로, 다르면 두 번째 값으로 비교합니다.

당시 예제에서는 뺄셈으로 비교했습니다. 큰 정수끼리 빼면 오버플로가 날 수 있으므로 모든 정수 범위에 안전한 비교는 아닙니다.

Java
Arrays.sort(arr, new Comparator<int[]>(){
@Override
public int compare(int[] o1, int[] o2) {
    if (o1[1] == o2[1]) {
        return o1[0] - o2[0];
    }
    return o1[1] - o2[1];
    }
});

Comparator는 추상 메서드가 하나인 함수형 인터페이스라서 람다식으로 구현할 수 있습니다. 비교 로직만 남기면 다음과 같습니다.

Java
Arrays.sort(arr, (int[] o1, int[] o2) -> {
    if (o1[1] == o2[1]) {
        return o1[0] - o2[0];
        }
        return o1[1] - o2[1];
    });

메서드 참조로 변환 함수 전달하기

문자열을 정수로 바꾸는 함수는 Integer::parseInt로 전달할 수 있습니다.

Java
str.stream().map(Integer::parseInt);

이 줄은 변환 단계를 정의할 뿐 아직 변환을 실행하지 않습니다. Stream은 단순한 반복자나 즉시 실행되는 for문과 달리 map, filter 같은 중간 연산을 지연 실행하므로 collect, forEach 같은 최종 연산이 있어야 처리가 진행됩니다. 자세한 실행 방식은 Java 8 Stream API 문서에 있습니다. 아래 전체 예제에서는 collect까지 호출해 변환한 값을 목록으로 모았습니다.

전체 예제

0부터 9까지 두 방식으로 출력한 뒤 짝수만 남깁니다. 문자열 목록은 정수로 변환해 출력합니다. 마지막에는 문자열에 9가 포함된 값만 출력합니다.

Java
package Java;

import java.util.*;
import java.util.stream.Collectors;

class Main {

    public static void main(String[] args) {

        ArrayList<Integer> arr = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            arr.add(i);
        }

        // forEach를 통해 리스트 요소의 개수 만큼 반복
        arr.stream().forEach(s -> System.out.println(s));
        System.out.println("=======================");
        arr.stream().forEach(System.out::println);
        System.out.println("=======================");
        // 리스트의 2로 나눈 나머지 값이 0인 값을 필터링 -> forEach로 반복 -> System.out 의 println 메소드로 출력
        arr.stream().filter(s -> s % 2 == 0).forEach(System.out::println);
        System.out.println("=======================");

        ArrayList<String> str = new ArrayList<>();
        str.add("281");
        str.add("182");
        str.add("192");

        // str의 요소룰 map을 통해 Integer 객체로 변환 -> collect를 통해 List 타입으로 변환 -> forEach를 통해 요소의 개수만큼 반복
        // ::의 용도는 Integer 클래스의 메소드를 수행하는 메소드 참조
        str.stream().map(Integer::parseInt).collect(Collectors.toList()).forEach(s -> System.out.println(s));
        System.out.println("=======================");
        // 9라는 문자열을 가진 요소를 필터링 -> 출력
        str.stream().filter(s -> s.contains("9")).forEach(System.out::println);
    }
}

당시 기록한 출력은 다음과 같습니다.

0
1
2
3
4
5
6
7
8
9
=======================
0
1
2
3
4
5
6
7
8
9
=======================
0
2
4
6
8
=======================
281
182
192
=======================
192