JDK8부터 지원한 API들로 Stream API는 데이터를 추상화하고 처리하는데 자주 사용되는 함수들을 정의해 두었다.
// Stream 사용 전
String[] nameArr = {"IronMan", "Captain", "Hulk", "Thor"}
List<String> nameList = Arrays.asList(nameArr);
// 원본의 데이터가 직접 정렬됨
Arrays.sort(nameArr);
Collections.sort(nameList);
for (String str: nameArr) {
System.out.println(str);
}
for (String str : nameList) {
System.out.println(str);
}
출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]
// Stream 사용 후
String[] nameArr = {"IronMan", "Captain", "Hulk", "Thor"}
List<String> nameList = Arrays.asList(nameArr);
// 원본의 데이터가 아닌 별도의 Stream을 생성함
Stream<String> nameStream = nameList.stream();
Stream<String> arrayStream = Arrays.stream(nameArr);
// 복사된 데이터를 정렬하여 출력함
nameStream.sorted().forEach(System.out::println);
arrayStream.sorted().forEach(System.out::println);
출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]
Stream API를 이용하면 코드의 라인수가 감소하고, 가독성은 높아진다.
Stream API 는 원본의 데이터를 조회하여 원본의 데이터가 아닌 별도의 요소들로 Stream을 생성한다.
그렇기 때문에 원본의 데이터로부터 읽기만 할 뿐이며, 정렬이나 필터링 등의 작업은 별도의 Stream 요소들에서 처리 된다.
List<String> sortedList = nameStream.sorted()
.collect(Collections.toList());
출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]
Stream API는 일회용이기 때문에 한 번 사용이 끝나면 재사용이 붙가능하다.
Stream이 또 필요한 경우에는 Stream을 다시 생성해주어야 한다.
만약 닫힌 Stream을 다시 사용해야한다면 IllegalStateException이 발생하게 된다.
userStream.sorted().forEach(System.out::print);
// 스트림이 이미 사용되어 닫혔으므로 에러 발생
int count = userStream.count();
// => IllegalStateException 발생
java.lang.IllegalStateException: stream has already been operated upon or closed
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
at java.util.stream.ReferencePipeline.noneMatch(ReferencePipeline.java:459)
출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]
Stream을 이용하면 코드가 간결해지는 이유 중 하나는 '내부 반복' 때문이다.
기존에는 반복문을 사용하기 위해 for문이나 while문 등과 같은 문법을 사용해야 했지만, Stream에서는 그러한 반복 문법을 메소드 내부에 숨기고 있기 때문에 보다 간결한 코드의 작성이 가능하다.
// 반복문이 forEach라는 함수 내부에 숨겨져 있다.
nameStream.forEach(System.out::println);
출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]
Stream은 데이터를 처리하기 위해 다양한 연산들을 지원한다.
Stream이 제공하는 연산을 이용하면 복잡한 작업들을 간단히 처리할 수 있는데, Stream에 대한 연산은 크게 생성하기, 가공하기, 결과 만들기 3가지 단계로 나눌 수 있다.
Stream 연산을 하기 위해서는 먼저 Stream 객체를 먼저 생성해주어야 한다.
배열, 컬렉션, 임의의 수, 파일 등 거의 모든 것을 가지고 스트림을 생성할 수 있다.
여기서 중의할 점은 연산이 끝나면 Stream이 닫히기 때문에, Stream이 닫힐 경우 다시 Stream을 생성해주어야 한다.
가공하기 단계는 원본의 데이터를 별도의 데이터로 가공하기 위한 중간 연산의 단계이다.
어떤 객체의 Stream을 원하는 형태로 처리할 수 있으며, 중간 연산의 반환 값은 Stream이기 때문에 필요한 만큼중간 연산을 연결하여 사용할 수 있다.
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList
.stream() // 생성하기
.filter(s -> s.startsWith("c")) // 가공하기
.map(String::toUpperCase) // 가공하기
.sorted() // 가공하기
.count(); // 결과만들기
출처: https://mangkyu.tistory.com/112 [MangKyu's Diary:티스토리]