-
Stream vs for loopJava & Spring 2024. 5. 19. 16:06
Java 8부터 사용이 가능한 Stream은 배열과 Collection의 데이터 처리에 초점을 둔 기능이다.
평소에 나는 업무 시 코드량을 줄이고 가독성을 높이려고 Stream을 사용하곤 했다. 알고리즘을 풀때면 for 문을 줄줄이 쓰기보단 단 몇줄의 Stream을 좀 더 선호했었다. 그러다가 Stream을 사용하다 제한시간을 통과하지 못한 케이스가 있어, Stream과 전통적인 loop을 비교해 알아봤다.
결론부터 말하자면, Stream은 일단 테스트 데이터가 매우 많아야 효율적이다. 또는 각 원소마다 컴퓨팅 연산이 오래 걸릴 수록 Stream 사용이 적합하다. 그렇다고 for loop이 나쁘냐? 그것도 아니다. for loop이 일반적으로 Stream보다 빠르다.
내가 파악하기로 Stream보다 for loop의 성능이 더 떨어지는 경우는 다음 조건일 때다.
1. 각 원소마다의 연산이 오래걸린다. (아파치 라이브러리의 slowSin() 같은.... )
2. 병렬 Stream이 가능한 경우 (연산이 오래걸리면 병렬 처리할 때가 더 빠른 경우가 있다. LinkedList 연산은 병렬스트림이 더 느림....)
그 외에는 Stream 성능이 좀 더 뒤쳐지거나, 비슷한 (데이터가 많을 경우) 수준이다.
프로그래머스 최댓값과 최솟값 문제를 전에 Stream으로 풀었던게 생각나서 for loop로 풀었을 때랑 비교해봤다.
<Stream 풀이>
public static String solution(String s) { long startTime = System.currentTimeMillis(); String[] numArr = s.split(" "); int max = Arrays.stream(numArr) .mapToInt(n -> Integer.valueOf(n)) .max().getAsInt(); int min = Arrays.stream(numArr) .mapToInt(n -> Integer.valueOf(n)) .min().getAsInt(); long endTime = System.currentTimeMillis(); System.out.println((endTime - startTime)); return min + " " + max; } public static void main(String[] args) { // Stream으로 풀이했을 경우 시간 //String s = "1 2 3 4"; // 44ms //String s = "-1 -2 -3 -4"; // 42ms //String s = "-1 -1"; // 43ms System.out.println(solution(s)); }
< for loop 풀이 >
public static String solution2(String s){ long startTime = System.currentTimeMillis(); String[] numArr = s.split(" "); int max = Integer.valueOf(numArr[0]); int min = Integer.valueOf(numArr[0]); int temp; for(int i = 0; i<numArr.length; i++){ temp = Integer.valueOf(numArr[i]); if(max < temp){ max = temp; } } for(int i = 0; i<numArr.length; i++){ temp = Integer.valueOf(numArr[i]); if(min > temp){ min = temp; } } long endTime = System.currentTimeMillis(); System.out.println((endTime - startTime)); return min + " " + max; } public static void main(String[] args) { //String s = "1 2 3 4"; // 1ms //String s = "-1 -2 -3 -4"; // 1ms //String s = "-1 -1"; // 1ms System.out.println(solution2(s)); }
스트림이 훨씬 느린것을 볼 수 있다. 데이터 수 가 일단 매우 적고, 원소별 연산이 어렵지 않기 때문에 스트림 풀이는 정답은 맞았으나, 잘못된? 선택이었던거 같다.
스트림은 대용량 데이터처리 + CPU 성능까지 이용할 상황에 적합한 것 같다. 그리고 스트림의 단점(?)이라기 보단 함수형 프로그래밍의 단점이라고 생각하는 부분이.... 디버깅하기가 좀 귀찮다... for loop에 비해...
하지만 코드량을 줄이고 가독성을 높일 수 있음에는 이견이 없다. 알고리즘 공부에는 뭐 내입맛대로 하겠지만, 업무에서 사용할때는 성능을 중요시 하는 상황인지, 코드 유지보수를 중요시 하는지를 좀 따져보고 사용하면 될 것 같다.
<참고>
'Java & Spring' 카테고리의 다른 글
API 에러 응답 논쟁 (2) 2024.09.19 EDI 구축 회고록 (1) 2024.08.29 소셜 로그인 회고 (Spring Security) (0) 2024.02.04