Java

[Java] Stream

Tommy__Kim 2024. 1. 24. 08:06

Stream이란 무엇인가?

Java 8에 새로 추가된 기능으로 스트림을 사용하면 선언형으로 Collection 데이터들을 처리 할 수 있다. 

 

예를 들어 칼로리가 400 미만인 요리들을 정렬해 Collection에 저장한다고 가정을 했을 때 스트림을 사용하지 않으면 다음과 같이 구현할 수 있다. 

List<Dish> lowCaloricDishes = new ArrayList<>();
for(Dish dish : menu) {
	if (dish.getCalories() < 400){
		lowCaloricDishes.add(dish);
    }
}
Collections.sort(lowCaloricDishes, new Comparator<Dish>(){
	public int compare(Dish dish1, Dish dish2){
    	return Integer.compare(dish1.getCalories(), dish2.getCalories());
    }
}

 

스트림을 사용하면 다음과 같이 구현할 수 있다. 

List<String> lowCaloricDishes = 
	menu.stream()
	.filter(d -> d.getCalories() < 400)
	.sorted(campring(Dishes::getCalories))
	.collect(toList());

 

스트림 API의 특징은 다음과 같다. 

  • 선언형 : 더욱 간결하고 가독성이 좋아진다.
  • 조립할 수 있음 : 유연성이 좋아진다.
  • 병렬성 : 성능이 좋아진다. 

Stream의 특징 

1. 딱 한번만 탐색할 수 있다.

탐색된 스트림의 요소는 소비되므로, 반복자와 마찬가지로 스트림도 단 한번만 탐색 가능하다.

반복자와 마찬가지로 한번 탐색된 요소를 다시 탐색하려면 초기 데이터 소스에서 새로운 스트림을 만들어야 한다. 

2. 내부 반복

Collection 인터페이스를 사용 할 때 사용자가 직접 요소를 반복하는 경우를 외부 반복이라 하며, 반복을 알아서 처리하고, 결과 스트림 값을 어딘가에 저장해 주는 경우를 내부 반복이라고 한다. Stream API는 내부 반복을 지원한다. 

 

외부 반복 예시

List<String> names = new ArrayList<>();
for(Dish dish : menu) {
	names.add(dish.getName());	// 사용자가 직접 추가해 주어야 한다.
}

 

내부 반복 예시

List<String> names = menu.stream()
	.map(Dish::getName)
	.collect(toList());

 

Stream 라이브러리의 경우 내부 반복은 데이터 표현과 하드웨어를 활용한 병렬성 구현을 자동으로 선택하기 때문에 병렬성을 따로 관리할 필요가 없다. 

Stream 연산 

연결할 수 있는 스트림 연산을 중간 연산이라고 하며, 스트림을 닫는 연산을 최종 연산이라고 한다.

중간 연산

중간 연산은 다른 스트림을 반환한다. 그렇기 때문에 여러 중간 연산을 연결해 질의를 만들 수 있다.

중간 연산은 게으르다. 다시 말해 단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다. 

연산 형식 반환형식 연산의 인수 함수 디스크립터
filter 중간 연산 Stream<T> Predicate<T> T -> boolean
map 중간 연산 Stream<T> Function<T, R> T -> R
limit 중간 연산 Stream<T>    
sorted 중간 연산 Stream<T> Comparator<T> (T, T) -> int
distinct 중간 연산 Stream<T>    

최종 연산

최종 연산은 스트림 파이프라인에서 결과를 도출한다. 보통 최종 연산에 의해 List, Integer, void등 스트림 이외의 결과가 반환된다.

연산 형식 반환 형식 목적
forEach 최종 연산 void 스트림의 각 요소를 소비하며 람다를 적용 
count 최종 연산 long(generic) 스트림의 요소 개수를 반환
collect 최종 연산   스트림을 reduce해 리스트, 맵, 정수 형식의 컬렉션 생성