[ Java ] Stream과 반복문의 성능 차이 비교

5tr1ker·2024년 6월 17일
0

Java

목록 보기
7/8
post-thumbnail

개요

코드를 작성하다보면 for문과 stream문을 이용하여 리스트 내의 모든 요소에 접근하는 로직을 자주 볼 수 있습니다.
stream은 for문 보다 더 좋은 가독성을 갖고 있지만 여전히 for문을 사용하는 경우가 있는데, stream과 for문 로직을 보면서 어떤 로직이 더 좋은 성능을 갖고있는지, stream이 for문을 완전 대체할 수 있는지 구별하는 글을 담고 있습니다.

for문과 stream의 차이점

일반 for문향상된 for문Stream
형식for(초기화 ; 조건 ; 후처리 )for (변수 : 리스트)Stream 생성 -> 중간 연산 -> 최종 연산
등장 시기Java 1Java 5Java 8
특징빠른 성능높은 가독성 & 안정성가독성 증가

일반 for문

// 많이 사용되는 for문
String arr[] = new String[] {"a" , "b" , "c"};
        for(int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }

향상된 for문

String arr[] = new String[] {"a" , "b" , "c"};
        for(String data : arr) {
            System.out.println(data);
        }

일반 for문과 차이점은 java.lang.IndexOutOfBoundsException 예외를 마주치는 상황을 예방할 수 있습니다.

배열 내에 인덱스로 반복하는것이 아니라 배열 내의 원소 하나씩 반복하기 때문에 안정성이 높습니다.

Stream 객체

public void introduceStream(List<Integer> numbers){
	return numbers.stream()
    			.filter(number -> number > 5)
                .map(Distance::new)
                .collect(Collectors.toList());
}

for와 Stream의 특징

for문

for문의 경우 코드 블록을 사용합니다.

빨간 네모로 쳐져있는 부분은 하나의 코드블록으로 설명할 수 있습니다.

Stream 객체

Stream은 파이프라인을 사용하고 함수 객체로 표현되어, 람다식이나 메서드 참조가 가능합니다. 이는 표현을 간결하게 해주어 가독성 증가에 좋은 영향을 줄 수 있습니다.

  • 람다 표현식
    Stream은 람다식으로 요소 처리 코드를 제공합니다. Stream이 제공하는 대부분 요소는 함수형 인터페이스이며 ,람다식이기 때문에 지역 변수를 수정할 수 없는 단점이 존재합니다. 이는 final로 선언된 변수만 조회할 수 있습니다.

  • 생성, 중간처리, 최종 처리
    Stream은 생성, 중간처리, 최종 처리 3단계로 구분되로 로직이 작동합니다.

  • 재사용 불가능
    스트림은 생성되고, 중간처리를 거쳐 최종 처리로 가게되면 Stream이 종료됩니다. 이미 닫힌 Stream은 재사용할 수 없으며 Stream을 재사용할 경우 예외가 발생합니다.

  • continue, break 사용 불가
    Stream은 continue와 break 사용이 불가합니다. 사용해야 하는 경우 for문을 사용합니다.

어떤 것을 사용할까?

가독성

때에 따라 다릅니다

위의 경우 중첩된 if문으로 들여쓰기가 상당이 많이 된것을 볼 수 있습니다.
밑에 stream문을 보면 filter 를 사용하여 if문을 대신 사용하여 가독성이 좋아진 모습을 볼 수 있습니다.

다른 예시로 중첩 for문을 사용하여 구구단을 계산한 것을 볼 수 있습니다.
위의 코드에서는 중첩 for문이 stream 보다 가독성이 좋은 것을 볼 수 있습니다.

디버깅

Stream의 경우 내부 메서드들을 참조하는 형식이기 때문에 스택 트레이싱이 다소 어렵습니다.
지연 연산의 특징을 갖고 있어 순차적인 에러 트레이싱이 어렵습니다. 지연 연산에 대한 설명은 해당 블로그 에서 확인할 수 있습니다

반대로 for문의 경우 오류가 한눈에 보기 쉽습니다.

성능

원시 데이터

원시 데이터의 경우 stream보다 for문이 7배 가량 더 빠른 것을 볼 수 있습니다. 이는 원시 타입의 데이터를 처리할 땐 for문을 사용하는 것이 더 빠른 것을 볼 수 있습니다.

stream과 달리 for문은 Java1 부터 나왔기 때문에 JVM 내부에서 최적화가 잘 되어있기 때문입니다.

또한 for문은 단순 인덱스 기반으로 메모리에 바로 접근하기 때문에 오버 헤드가 없지만, Stream의 경우 JVM 처리 ( Stream 객체 생성, Stream에 필요한 객체 생성 , Wrapper 클래스의 박싱 / 언박싱 )이 있어 오버헤드가 존재합니다.

참조 데이터

ArrayList와 같은 참조 데이터 형식은 for문과 stream 시간 차이는 크게 나지 않습니다. ( 물론 for문이 조금 더 빠르다. )

ArrayList는 순회하는 비용이 크기때문에 for문과 stream 차이가 없습니다.

시간 복잡도에 따른 차이

함수 내부에 시간 복잡도가 충분히 클때 ( 데이터의 양이 많을 때 ) for문과 stream의 차이는 미미합니다.

테스트

원시 데이터

// 10 size
for-loop: 0ms
Stream: 3596ms

// 1,000 size
for-loop: 14ms
Stream: 4035ms

// 10,000 size
for-loop: 144ms
Stream: 5477ms

// 100,000 size
for-loop: 1367ms
Stream: 21874ms

참조 데이터

// 10 size
for-loop: 12ms
Stream: 867ms

// 1,000 size
for-loop: 543ms
Stream: 1071ms

// 10,000 size
for-loop: 1961ms
Stream: 1750ms

// 100,000 size
for-loop: 9156ms
Stream: 6173ms

?? 참조 데이터의 경우 데이터가 방대해질수록 stream이 for 문 보다 더 빠릅니다..
pc마다 차이가 있을 수 있지만 의외의 결과나 나온 것을 볼 수 있습니다.

정리

  • 원시 타입만 반복하는 경우에 for문을 사용하는 것이 더 빠르다.
  • 참조 데이터를 순회할 땐 for문과 stream의 차이는 없지만 for문이 살짝 더 빠르다.
  • 데이터의 양이 많을 땐 for문과 stream에 대한 차이는 거의 없다.
  • 가독성과 유지보수 측면에서는 for문보다 stream이 더 좋다
  • stream은 filter, reduce와 같은 여러 함수를 사용할 때 가독성이 더 좋아진다.
  • 단순 forEach 혹은 컬렉션의 forEach는 stream보다 좋다. ( 다만 데이터 양이 많아질수록 차이는 없어진다. )

참고

참고 블로그 1 : https://velog.io/@foureaf/JAVA-For%EA%B3%BC-Stream%EC%9D%80-%EC%96%B4%EB%96%A4-%EC%B0%A8%EC%9D%B4%EA%B0%80-%EC%9E%88%EB%8A%94%EA%B1%B8%EA%B9%8C
참고 블로그 2 : https://pamyferret.tistory.com/49
참고 블로그 3 : https://velog.io/@tjdtn0219/JavaStream-%EA%B0%9C%EB%85%90-%EC%84%B1%EB%8A%A5-%EC%82%AC%EC%9A%A9-%EC%98%88%EC%A0%9Cfeat.-for%EB%AC%B8-%EB%B9%84%EA%B5%90#:~:text=Stream%20VS%20For%2Dloop,-primitive%20type(%EC%9B%90%EC%8B%9C&text=%EB%B0%B0%EC%97%B4%EC%9D%98%20%EA%B2%BD%EC%9A%B0%20Index%EB%A5%BC,%EA%B0%80%20%EB%B0%9C%EC%83%9D%ED%95%98%EC%97%AC%2C%20%EB%8D%94%20%EB%8A%90%EB%A6%AC%EB%8B%A4.

profile
https://github.com/5tr1ker

0개의 댓글