STREAM API - 정의 (1/5)

Jimin·2024년 3월 12일
0

JAVA

목록 보기
23/25

Stream API란?

JDK8부터 지원한 API들로 Stream API는 데이터를 추상화하고 처리하는데 자주 사용되는 함수들을 정의해 두었다.

Stream API의 예시

Stream API 사용 이전 코드

// Stream 사용 전
String[] nameArr = {"IronMan", "Captain", "Hulk", "Thor"}
List<String> nameList = Arrays.asList(nameArr);

// 원본의 데이터가 직접 정렬됨
Arrays.sort(nameArr);
Collections.sort(nameList);

for (String str: nameArr) {
  System.out.println(str);
}

for (String str : nameList) {
  System.out.println(str);
}

출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]

Stream API 사용 이후 코드

// Stream 사용 후
String[] nameArr = {"IronMan", "Captain", "Hulk", "Thor"}
List<String> nameList = Arrays.asList(nameArr);

// 원본의 데이터가 아닌 별도의 Stream을 생성함
Stream<String> nameStream = nameList.stream();
Stream<String> arrayStream = Arrays.stream(nameArr);

// 복사된 데이터를 정렬하여 출력함
nameStream.sorted().forEach(System.out::println);
arrayStream.sorted().forEach(System.out::println);
출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]

Stream API의 특징

Stream API를 이용하면 코드의 라인수가 감소하고, 가독성은 높아진다.

  1. 원본의 데이터를 변경하지 않는다.
  2. 일회용이다.
  3. 내부 반복으로 작업을 처리한다.

1. 원본의 데이터를 변경하지 않는다.

Stream API 는 원본의 데이터를 조회하여 원본의 데이터가 아닌 별도의 요소들로 Stream을 생성한다.
그렇기 때문에 원본의 데이터로부터 읽기만 할 뿐이며, 정렬이나 필터링 등의 작업은 별도의 Stream 요소들에서 처리 된다.

List<String> sortedList = nameStream.sorted()
							.collect(Collections.toList());
출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]

2. 일회용이다.

Stream API는 일회용이기 때문에 한 번 사용이 끝나면 재사용이 붙가능하다.
Stream이 또 필요한 경우에는 Stream을 다시 생성해주어야 한다.
만약 닫힌 Stream을 다시 사용해야한다면 IllegalStateException이 발생하게 된다.

userStream.sorted().forEach(System.out::print);

// 스트림이 이미 사용되어 닫혔으므로 에러 발생
int count = userStream.count(); 

// => IllegalStateException 발생
java.lang.IllegalStateException: stream has already been operated upon or closed
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
    at java.util.stream.ReferencePipeline.noneMatch(ReferencePipeline.java:459)
출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]

3. 내부 반복으로 작업을 처리한다.

Stream을 이용하면 코드가 간결해지는 이유 중 하나는 '내부 반복' 때문이다.
기존에는 반복문을 사용하기 위해 for문이나 while문 등과 같은 문법을 사용해야 했지만, Stream에서는 그러한 반복 문법을 메소드 내부에 숨기고 있기 때문에 보다 간결한 코드의 작성이 가능하다.

 // 반복문이 forEach라는 함수 내부에 숨겨져 있다.
nameStream.forEach(System.out::println);
출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]

Stream API의 연산 종류

Stream API의 3가지 단계

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

  1. 생성하기
  2. 가공하기
  3. 결과 만들기

1. 생성하기

  • Stream 객체를 생성하는 단계
  • Stream 은 재사용이 불가능하므로 닫히면 다시 생성해주어야 한다.

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

2. 가공하기

  • 원본의 데이터를 별도의 데이터로 가공하기 위한 중간 연산
  • 연산 결과를 Stream으로 다시 반환하기 때문에 연속해서 중간 연산을 이어갈 수 있다.

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

3. 결과 만들기

  • 가공된 데이터로부터 원하는 결과를 만들기 위한 최종 연산
  • Stream의 요소들을 소모하면서 연산이 수행되기 때문에 1번만 처리 가능하다.

Stream 연산 예시 코드

List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");

myList
    .stream()							// 생성하기
    .filter(s -> s.startsWith("c"))			// 가공하기
    .map(String::toUpperCase)			// 가공하기
    .sorted()							// 가공하기
    .count();							// 결과만들기
    
출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]
profile
https://github.com/Dingadung

0개의 댓글