스트림(Stream)과 람다식의 이해: 함수형 프로그래밍과 스트림까지

손지민·2024년 8월 15일

Java 기초

목록 보기
13/13
post-thumbnail

이번 글에서는 자바의 스트림(Stream)과 람다식(Lambda Expression)에 대해 알아봅니다. 스트림과 람다식은 자바 8에서 도입된 강력한 기능들로, 자바 프로그래밍의 생산성과 가독성을 크게 향상시킵니다. 이 글에서는 지역 내부 클래스와 익명 클래스의 개념에서 출발하여, 이를 람다식과 스트림으로 변환하는 과정을 단계별로 설명합니다. 또한, 함수형 프로그래밍의 개념을 통해 왜 스트림과 람다식이 중요한지 알아봅니다.

이 글에서 다룰 주요 키워드

  • 함수형 프로그래밍: 순수 함수를 조합하여 프로그램을 구성하는 프로그래밍 패러다임으로, 부수 효과를 최소화하고 데이터 처리를 더 명확하게 만듭니다.
  • 지역 내부 클래스: 메서드 내부에 정의된 클래스로, 외부 클래스의 메서드 내에서만 사용 가능.
  • 익명 클래스: 이름이 없는 클래스. 주로 일회성으로 특정 인터페이스를 구현할 때 사용.
  • 람다식: 함수형 인터페이스의 단일 추상 메서드를 간결하게 표현한 문법.
  • 스트림(Stream): 자바 8에서 도입된 기능으로, 컬렉션이나 배열의 요소를 함수형 스타일로 처리할 수 있는 API.

1. 함수형 프로그래밍 (Functional Programming)

함수형 프로그래밍은 프로그래밍 패러다임 중 하나로, 프로그램의 로직을 순수 함수(pure function)를 이용해 구성하는 방식입니다. 여기서 순수 함수란, 같은 입력에 대해 항상 같은 출력을 반환하며, 함수 외부의 상태를 변경하지 않는 함수를 말합니다. 함수형 프로그래밍은 부수 효과(side effect)를 최소화하여 코드의 안정성과 예측 가능성을 높입니다.

자바 8에서 도입된 람다식과 스트림 API는 이러한 함수형 프로그래밍의 개념을 자바에 도입한 대표적인 예입니다.


2. 지역 내부 클래스 (Local Inner Class)

지역 내부 클래스는 메서드 내부에 선언된 클래스로, 해당 메서드 내에서만 사용할 수 있습니다. 이 클래스는 메서드 내에서 특정 작업을 수행하기 위해 주로 사용됩니다.

예제 코드: 지역 내부 클래스

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

        // 지역 내부 클래스 사용
        class PrintConsumer implements Consumer<String> {
            @Override
            public void accept(String name) {
                System.out.println(name);
            }
        }

        names.forEach(new PrintConsumer());
    }
}

위 예제에서 PrintConsumer 클래스는 Consumer<String> 인터페이스를 구현하며, forEach() 메서드를 통해 리스트의 각 요소를 출력합니다.

  • 이때, forEach() 메서드는 전달된 Consumer 객체의 accept() 메서드를 호출하여 작업을 수행합니다.

3. 익명 클래스 (Anonymous Class)

익명 클래스는 이름이 없는 클래스입니다. 지역 내부 클래스를 간소화한 형태로, 일회성으로 특정 인터페이스를 구현할 때 사용됩니다.

예제 코드: 익명 클래스

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

        // 익명 클래스 사용
        names.forEach(new Consumer<String>() {
            @Override
            public void accept(String name) {
                System.out.println(name);
            }
        });
    }
}

위 코드에서 forEach() 메서드에 Consumer 인터페이스를 구현한 익명 클래스를 전달합니다. 익명 클래스는 지역 내부 클래스와 달리 별도의 클래스 정의 없이 즉석에서 구현할 수 있습니다.

  • 이때도 forEach() 메서드는 전달된 익명 클래스 객체의 accept() 메서드를 호출하여 리스트의 각 요소를 출력합니다.

4. 람다식 (Lambda Expression)

람다식은 자바 8에서 도입된 문법으로, 함수형 인터페이스의 단일 추상 메서드를 간결하게 구현할 수 있는 방법입니다. 익명 클래스를 더 간단하게 표현할 수 있습니다.

람다식은 함수형 프로그래밍의 핵심 요소로, 코드의 가독성과 유지보수성을 크게 향상시킵니다. 람다식은 특히 간단한 연산을 수행하거나, 콜백 함수를 정의할 때 유용합니다.

예제 코드: 람다식

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

        // 람다식 사용
        names.forEach(name -> System.out.println(name));
    }
}

람다식 name -> System.out.println(name)Consumer<String> 인터페이스의 accept() 메서드를 구현한 것입니다. 이를 통해 코드가 훨씬 간결해졌습니다.

  • forEach() 메서드는 이 람다식을 전달받아 각 요소에 대해 accept() 메서드를 호출합니다.

5. 스트림 (Stream)

스트림(Stream) 은 자바 8에서 도입된 API로, 컬렉션이나 배열의 요소들을 함수형 스타일로 처리할 수 있게 해줍니다. 스트림은 데이터를 처리하는 다양한 중간 연산(필터링, 매핑 등)과 최종 연산(수집, 반복 등)을 제공합니다.

스트림은 함수형 프로그래밍의 또 다른 예로, 데이터를 일관되게 처리할 수 있도록 돕습니다. 스트림을 사용하면 코드가 더 간결해지고, 병렬 처리가 가능해 성능이 향상됩니다.

예제 코드: 스트림과 람다식

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

        // 스트림을 사용한 처리
        names.stream()
            .sorted()
            .forEach(name -> System.out.println(name));
    }
}

위 예제에서는 stream() 메서드를 사용해 스트림을 생성한 후, sorted() 중간 연산을 추가하여 리스트의 요소를 정렬한 뒤 forEach() 메서드로 출력합니다. 이처럼 스트림은 중간 연산과 최종 연산을 결합하여 복잡한 데이터 처리를 간결하게 표현할 수 있습니다.


추가 정보: 인터페이스의 기본 메서드와 자바 표준 라이브러리

자바 8부터 인터페이스는 기본 메서드를 가질 수 있게 되었습니다. 기본 메서드는 인터페이스에서 구현된 메서드로, 인터페이스를 구현하는 클래스에서 필수적으로 오버라이드하지 않아도 됩니다.

IterableStream 인터페이스 모두 forEach() 메서드를 기본 메서드로 제공합니다.

또한, java.lang 패키지에 속하는 클래스들은 별도의 import 없이 사용할 수 있지만, java.util.stream 패키지의 클래스들은 필요한 경우 import해야 합니다.


결론

자바에서 스트림과 람다식을 사용하면 코드의 가독성을 크게 높일 수 있으며, 함수형 프로그래밍의 이점을 적극 활용할 수 있습니다. 스트림 API는 복잡한 데이터 처리 작업을 간결하게 표현할 수 있는 도구로, 자바 8 이후의 자바 개발에서 매우 중요한 역할을 합니다. 이번 글에서 설명한 함수형 프로그래밍, 지역 내부 클래스, 익명 클래스, 람다식, 그리고 스트림의 개념과 사용법을 잘 이해하고, 실제 개발에 활용해 보시길 바랍니다.

profile
Developer

0개의 댓글