[JAVA] Stream API (feat. 람다식, 함수형 인터페이스)

SCY·2023년 1월 31일

자바의 람다식을 검색하기 시작했더니 어느새 Stream API를 공부하고 있었다.
이왕 공부하는 김에 같이 알아보자.

Stream API

자바8부터 지원되며 순차적인 계산 처리(함수형 프로그래밍)가 가능하다.
데이터를 추상화하고 처리하는 데 자주 사용되는 함수들이 정의되어있다.

Stream의 효력을 알아보기 위해 코드 전후를 비교해보자.

String[] nameArr = {"MinSu", "SuJin", "ChunSik", "YoungJa"};
List<String> nameList = Arrays.asList(nameArr);

위 정의된 배열과 리스트를 정렬해보자.

  • Stream 사용 전

    Arrays.sort(nameArr);
    Collections.sort(nameList);
    
    for (String str : nameArr) {
        System.out.println(str);
    }
    for (String str : nameList) {
        System.out.println(str);
    }

    원본의 데이터가 직접 정렬된다.

  • Stream 사용 후

    Stream<String> nameStream = nameList.stream();
    Stream<String> arrayStream = Arrays.stream(nameArr);
    
    nameStream.sorted().forEach(System.out::println);
    arrayStream.sorted().forEach(System.out::println);

    복사된 데이터를 정렬한다. 훨씬 간결하고 가독성이 높다.

특징

  • 원본의 데이터를 변경하지 않음
  • 일회용 (한 번 사용하면 끝)
  • 내부 반복으로 작업을 처리함 (ex. forEach())

연산 과정

myList
	.stream() //생성하기
	.filter(member -> member.getName().equals(name)) //가공하기
	.findAny(); //결과만들기

위와 같이 생성 - 가공 - 결과의 연산 과정을 거친다.

  1. 생성 - 닫히면 다시 만들어주어야 함
  2. 가공 - 반환값이 모두 Stream이기에 연산 간의 연결이 가능
  3. 결과 - Stream의 요소를 소모하며 진행되므로 1번만 가능

자세한 내용은 다음 글에 포스팅.


Stream API를 공부할 때 알아두면 좋은
lambda와 함수형 인터페이스에 대해 간단히 짚어보자.

람다식 (lambda expression)

람다식은 함수를 하나의 식으로 표현한 것이다.
함수의 이름이 필요 없어 익명 함수로 생각할 수 있다.

파이선에서는 람다 함수를 lambda라는 문자 그대로 사용했는데
자바에서는 () -> {} 방식을 사용한다.

public String hello() {
    return "Hello World!";
}

() -> "Hello World!"; // lambda expression

위 두 코드는 같은 기능을 수행한다.
람다식 사용 시 코드가 간결해져 가독성이 높아진다.
하지만 재사용이 불가능하고 남발하면 코드가 지저분해질 수 있다.

함수형 인터페이스 (functional interface)

함수를 변수처럼 선언 가능하다.

public class Lambda {
	public static void main(String[] args) {
    	System.out.println(new MyLambdaFunction() {
			public int max(int a, int b) {
				return a > b ? a : b;
			}
		}.max(3, 5));
    }
}

위 함수를 람다와 함수형 인터페이스를 이용해 리팩토링해보자.

@FunctionalInterface
interface MyLambdaFunction {
	int max(int a, int b);
}

public class Lambda {
	public static void main(String[] args) {
    	MyLambdaFunction mlf = (int a, int b) -> a > b ? a : b ;
        mlf.max(2, 10);
    }
}

구현

  • 인터페이스 내부에 1개의 abstract 함수 선언 (하나만 가능)
  • @FunctionalInterface 어노테이션 붙이기

선언

  • 람다식으로 생성된 순수 함수는 함수형 인터페이스로만 선언 가능
  • 다른 방법으로는 이름을 정의할 수 없음

다음 글에서는 Stream API 연산에 대해 자세히 다룰 것.

자세한 내용 참고

profile
성장 중독 | 서버, 데이터, 정보 보안을 공부합니다.

0개의 댓글