스트림(Stream) 개념, 특징
in Development on Java
스트림(Stream)이란?
스트림(Stream)의 기능이 생겨난 이유
많은 수의 데이터를 다룰 때, Collection(List, ArrayList, Set, HashSet 등)이나 Array(배열)을 활용했었다. 이 때, for문과 Iterator를 사용해서 코드를 작성할 때면 코드가 너무 길어지고 알아보기 어려웠었다. 또한 정렬을 수행하려고 할 때, 자료 구조(Collection, Array 등)에 따라서 Collections.sort()
, Arrays.sort()
와 같이 다른 메서드를 사용해야 하는 것이 불편했다.
이렇나 문제점들을 해결하기 위해서 만든 것이 ‘스트림(Stream)’이다. 스트림은 데이터 소스를 추상화하고, 데이터를 다루는 데 자주 사용되는 메서드들을 정의해 놓았다. 데이터 소스를 추상화하였다는 것은, 데이터 소스가 Collection이건 Array건 상관없이 같은 방식으로 다룰 수 게 되었다는 것이다. 이로 인해 Collections.sort()
, Arrays.sort()
와 같이 각기 다른 데이터 소스마다 ‘정렬’과 같은 기능들을 각각 구현해주지 않아도 되므로 재사용성이 높아졌다.
데이터를 정렬하고 화면에 출력하는 밑의 코드를 보고 스트림(Stream)의 장점을 느껴보자.
스트림(Stream)을 사용하지 않은 경우
String[] strArr = { "aaa", "bbb", "ccc" };
List<String> strList = Arrays.asList(strArr);
Arrays.sort(strArr);
Collections.sort(strList);
for (String str : strArr) {
System.out.println(str);
}
for (String str : strList) {
System.out.println(str);
}
스트림(Stream)을 사용한 경우
String[] strArr = { "aaa", "ddd", "ccc" };
List<String> strList = Arrays.asList(strArr);
Stream<String> strStream1 = strList.stream();
Stream<String> strStream2 = Arrays.stream(strArr);
strStream1.sorted()
.forEach(System.out::println);
strStream2.sorted()
.forEach(System.out::println);
스트림(Stream) 한 줄 요약
많은 수의 데이터를 다루는 자료구조(List, Array 등)를 가독성 있고, 편하게 다룰 수 있도록 만들어주는 기능
스트림(Stream)의 특징
1. 데이터 소스를 변경하지 않는다.
스트림은 데이터 소스로부터 데이터를 읽기만할 뿐, 데이터 소스를 변경하지 않는다.
String[] strArr = { "aaa", "ddd", "ccc" };
System.out.println(Arrays.toString(strArr)); // 정렬 전 : [aaa, ddd, ccc]
Arrays.stream(strArr)
.sorted();
System.out.println(Arrays.toString(strArr)); // 정렬 후 : [aaa, ddd, ccc]
즉, 위의 예시에서 데이터 소스인 strArr
는 변경되지 않는다.
2. 스트림은 일회용이다.
스트림은 1회용이다. 한 번 사용하면 닫혀서 다시 사용할 수 없다. 필요하다면 스트림을 다시 생성해야 한다.
String[] strArr = { "aaa", "ddd", "ccc" };
Stream<String> strStream = Arrays.stream(strArr);
strStream.sorted().forEach(System.out::println);
strStream.sorted().forEach(System.out::println); // 에러 : 스트림이 이미 닫혔음
3. 스트림은 모든 요소에 대한 반복 처리를 ‘내부 반복’으로 처리한다.
스트림을 이용한 작업이 간결할 수 있는 비결중의 하나가 바로 ‘내부 반복’이다. 내부 반복이라는 것은 반복문을 메서드의 내부에 숨길 수 있다는 것을 의미한다. for문에 대한 긴 반복문을 forEach()
를 활용해서 내부로 로직을 숨겼다.
stream.forEach(System.out::println);
4. 스트림의 연산
스트림이 제공하는 다양한 연산을 이용해서 복잡한 작업들(정렬, 필터링 등)을 간단히 처리할 수 있다. 스트림이 제공하는 연산은 ‘중간 연산’과 ‘최종 연산’으로 분류할 수 있다.
- 중간 연산 : 연산결과를 스트림으로 반환 O. 중간 연산을 연속해서 연결할 수 있다.
- 최종 연산 : 연산결과를 스트림으로 반환 X. 스트림의 요소를 소모하므로 단 한번만 가능.