(p.10) '스트림이 처리하는 데이터(심지어 처리된 데이터)를 모두 메모리에 저장하지 않을 수도 있도록 설계되었다. 따라서 스트림을 이용하면 컴퓨터 메모리에 저장할 수 없는 큰 데이터도 문제없이 처리할 수 있다.'
자바의 스트림 API가 빅데이터를 다루기 좋은 이유는 속도가 아니라 메모리 측면에서 다뤄진다.
스트림은 요소들을 메모리에 저장하지 않는다. (반면 컬렉션은 모든 요소를 메모리에 저장한다.)
스트림은 Source(컬렉션, 배열, 입출력 채널 등)로부터 입력받은 데이터를 처리하여 Destination으로 전달하는 파이프라인의 일종이다.
출처 - https://medium.com/elevate-java/java-streams-an-in-memory-data-structure-d6984eea1091
이 때, Source로부터 전체 데이터를 한번에 읽어들이지 않고 chunk by chunk로 가져온다. 즉, 엄청난 크기의 전체 데이터를 저장하기 위한 버퍼가 필요하지 않다는 의미이다.
현재 나의 수준에서 스트림을 이용한 경우는 Source가 컬렉션인 경우 밖에 없다. 그래서 '메모리에 저장하지 않는다'는 내용이 잠시 이해되지 않았다. Source가 빅데이터를 다루는 Kafka라고 생각해보자. (Destination은 인메모리가 아닌 외부 어딘가) 스트림은 Source로부터 입력받는 데이터를 처리하는 과정에서 전체 데이터를 수용하기 위한 공간은 할당하지 않기 때문에 자바 애플리케이션에서 메모리 걱정없이 빅데이터를 다룰 수 있는 도구가 된다.
<aside> ❓ 그렇다고 아예 메모리를 사용하지 않는 것은 아니고 중간 연산을 처리하는 과정에서 RAM은 사용하지 않을까? 단지 그 크기가 전체가 아닌 chunk 수준으로 필요하기 때문에 빅데이터를 다루기엔 문제가 없는 것이 아닌지.
</aside>
스트림 API는 중간 연산과 최종 연산으로 분류할 수 있다.
최종 연산이 호출되기 전까지 중간 연산은 수행되지 않는다.
최종 연산의 내용에 따라 중간 연산을 모든 데이터에 수행하지 않을 수 있다. 모든 데이터가 아니라 필요한 만큼의 데이터에만 중간 연산을 수행하기도 한다는 의미이다.
Integer integer = Arrays.asList(10,3,13,4,1,52)
.stream()
.filter(number -> number % 2 == 0)
.findFirst()
.get();
최종 연산이 findFirst()
이기 때문에 10, 3, 13, 4, 1, 52
에 대해 filter
연산(중간 연산)을 수행하지 않는다. 첫 번째 요소인 10
에만 filter
를 수행하고 그 결과를 반환한다.
이러한 특징은 스트림의 병렬 처리와 더불어 자동으로 최적화하는 효과를 누릴 수 있게 해준다.
출처 - http://melonicedlatte.com/computerarchitecture/2019/10/15/143300.html