[Java] Stream

JiKwang Jeong·2022년 4월 21일
0

Stream API

JDK8부터 Stream API와 람다식, 함수형 인터페이스 등을 지원하면서 Java를 이용해 함수형 프로그래밍을 할 수 있는 API들을 제공하고 있다. 그 중 Stream API는 데이터를 추상화하고, 처리하는데 자주 사용되는 함수들을 정의해두었다. (데이터 종류에 상관 없이 같은 방식으로 데이터 처리 가능)

String[] a = {"Jeong", "Kim", "Choi", "Seok"}
List<String> list = Arrays.asList(a);

// 별도의 Stream 생성
Stream<String> aStream = a.stream();
Stream<String> listStream = Arrays.stream(list);

// 복사된 데이터 정렬하여 출력
aStream.sorted().forEach(System.out::println);
listStream.sorted().forEach(System.out::println);

다음과 같이 Stream API를 통해 가독성을 높이고 코드의 라인 수도 줄일 수 있다.

Stream API의 특징

  1. 원본의 데이터를 변경하지 않는다.
    Stream API는 원본의 데이터를 조회하여 원본의 데이터가 아닌 별도의 요소들로 Stream을 생성한다. 그렇기 때문에 원본의 데이터로부터 읽기만 할 뿐이며, 정렬이나 필터링 등의 작업은 별도의 Stream 요소들에서 처리가 된다.
List<String> list = listStream.sorted().colloct(Collections.toList());
  1. 일회용이다.
    Stream API는 일회용이기 때문에 한 번 사용이 끝나면 재사용이 불가능하다. Stream이 또 필요한 경우에는 Stream을 다시 생성해주어야 한다. 만약 닫힌 Stream을 다시 사용한다면 IllegalStateException이 발생한다.
listStream.sort().forEach(System.out::println);

// 스트림이 사용되어 닫힘
int count = listStream.count(); // -> IllegalStateException 발생
  1. 내부 반복으로 작업을 처리한다.
    Stream을 이용하면 코드가 간결해지는 이유 중 하나는 내부 반복때문이다. 기존에는 반복문을 사용하기 위해서 for이나 while 등과 같은 문법을 사용해야 했지만, stream에서는 그러한 반복 문법을 메소드 내부에 숨기고 있기 때문에 보다 간결한 코드의 작성이 가능하다.
listStream.forEach(System.out::println);

Stream API의 연산 종류

Stream API의 3가지 단계

Stream은 데이터를 처리하기 위해 다양한 연산들을 지원한다. Stream이 제공하는 연산을 이용하면 복잡합 작업들을 간단히 처리할 수 있는데, 스트림에 대한 연산은 크게 3가지 단계로 나뉜다.

  1. 생성하기
    - Stream 객체를 생성하는 단계
    - Stream은 재사용이 불가능하므로, 닫히면 다시 생성해주어야 한다.
    Stream 연산을 하기 위해서는 먼저 Stream객체를 생성해줘야 한다. 배열, 컬렉션, 임의의 수, 파일 등 거의 모든 것을 가지고 스트림을 생성할 수 있다. 여기서 주의할 점은 연산이 끝나면 Stream이 닫히기 때문에, Stream이 닫혔을 경우 다시 Stream을 생성해야 한다.

  2. 가공하기
    - 원본의 데이터를 별도의 데이터로 가공하기 위한 중간 연산
    - 연산 결과를 Stream으로 다시 반환하기 때문에 연속해서 중간 연산을 이어갈 수 있다.
    가공하기 단계는 원본의 데이터를 별도의 데이터로 가공하기 위한 중간 연산의 단계이다. 어떤 객체의 Stream을 원하는 형태로 처리할 수 있으며, 중간 연산의 반환값은 Stream이기 때문에 필요한 만큼 중간 연산을 연결하여 사용할 수 있다.

  3. 결과만들기

    • 가공된 데이터로부터 원하는 결과를 만들기 위한 최종 연산
    • Stream의 요소들을 소모하면서 연산이 수행되기 때문에 1번만 처리가 가능하다.
  • 예시
List<String> list = Arrays.asList("x1", "y1", "y2", "z1", "z2);

list.stream()							// 생성하기
	.filter(s -> s.startsWith("y"))		// 가공하기
    .map(String::toUpperCase)			// 가공하기
    .sorted()							// 가공하기
    .count();							// 결과만들기
profile
기억보다 기록, 난리보다 정리

0개의 댓글