Java의 Stream 인터페이스는 데이터 처리를 단순하고 읽기 쉽게 만들어주는 도구이다.
Collection(ArrayList, Map, Set 등)과는 다르다. 왜?
그럼 왜 Stream이 데이터 처리를 단순하고 읽기 쉽게 만들어주는 걸까?
private static void testExamList() {
List<Exam> examList = createList();
List<Exam> resultList = new ArrayList<>();
for (Exam exam : examList) {
if (exam.name().equals("홍길동")) {
resultList.add(exam);
}
}
resultList.sort(Comparator.comparingInt(Exam::score));
System.out.println(resultList);
}
바로 위와 같은 데이터 처리를 위한 코드를 간편하게 바꿔주기 때문인데,
그 이유를 설명하기 위해서는 Bulider Pattern에 대해 간단히 알아야 한다.
객체의 생성 과정을 단순화하고, 가독성과 유연성을 향상 시키는 디자인 패턴
//
Person person = new Person.Builder()
.name("giggle")
.age(25)
.address("apartment")
.build();
별도의 Builder 클래스를 만들어 메소드를 Step by Step으로 입력 받고,
최종적으로 Build 메서드로 인스턴스를 생성하여 Return 하는 패턴
정보) HttpClient, HttpRequest도 Builder Pattern의 클래스이다.
Builder 패턴을 쓰면 Stream에서 일어나는 연산과정을 메서드 체이닝 방식으로 표현 가능
Stream은 크게 3가지 단계로 나눠진다.
대표적으로 생성 방식은 두 가지가 있다.
Builder 메서드로 생성하기
Collection이 없거나, Stream에 들어갈 요소들을 순차적으로 추가하고 싶을 때 사용
public class Run {
public static void main(String[] args) {
testStream();
}
private static void testStream() {
Stream<Integer> iStream = Stream
.<Integer>builder()
.add(10).add(13).add(100).add(29)
.build();
List<Integer> list = iStream
.sorted((a, b) -> -(a-b))
.toList();
System.out.println(list);
}
}
기존에 가지고 있던 Collection으로부터 생성하기
우리가 가지고 있는 List(Collection) stream 메서드를 이용해 Stream 객체로 변환
public class Run {
public static void main(String[] args) {
testExamList();
}
private static List<Exam> createList() {
List<Exam> list = new ArrayList<>();
list.add(new Exam("국어", "홍길동", 90));
list.add(new Exam("수학", "푸바오", 100));
list.add(new Exam("영어", "푸바오", 100));
list.add(new Exam("과학", "홍길동", 46));
return list;
}
private static void testExamList() {
List<Exam> examList = createList();
List<Exam> streamList = examList.stream()
.filter(e -> e.name().equals("홍길동"))
.sorted(Comparator.comparingInt(Exam::score))
.toList();
System.out.println(streamList);
}
}
filter, map, sort, distinct, limit 등
여러 번 사용가능
원본 Stream을 변형하는 것이 아니라 각 단계마다 새로운 Stream을 생성
foreach, reduce, count, sum, average 등
합계나 평균을 구하거나 다른 형태의 데이터 Collection으로 변환하게 됨
최종 결과물을 얻기 위해 단 1번만 수행 가능.
중간 연산 중에는 약간 흐물흐물한 상태 > 한번 굳으면(결과 연산 수행) 더 이상 되돌릴 수 없다.
다시 데이터를 처리하고 싶다면, 새롭게 Stream을 생성하는 수 밖에 없음
I/O 에서는 반드시 Close를 해줘야 함 > Try with resources 구문에 적용가능즉, Stream 역시 AutoCloseable