반응형
스트림; Stream
- 데이터의 흐름
- java 8에서 추가한 람다를 활용할 수 있는 기술 중 하나
- 배열 / 컬렉션 인스턴스에 함수 여러 개를 조합해 원하는 결과를 필터링하고 가공된 결과를 얻을 수 있다.
- 한 번 종료 작업을 한 스트림에 대해서는 재사용 불가
- 병렬 처리* 가능 -> 여러 스레드가 작업
* 병렬 처리: 하나의 작업을 둘 이상으로 나눠 동시에 진행하는 것
스트림 구조
- 생성하기: 스트림 인스턴스 생성
- 가공하기: filtering, mapping 등 원하는 결과 만들기
- 결과 만들기: 최종 결과 만들어내는 작업
-> 객체.스트림생성().가공().결과만들기(); 식이다.
( 이렇게 연계할 수 있는 방식을 파이프라인이라 부른다고도 한다. )
1. 생성하기
주로 Collection, Arrays에서 쓰이고, I/O resources(ex: File), Generators, Stream ranges, Pattern 등에서도 쓰인다.
//Collection에서 스트림 생성
List<String> names = Arrays.asList("jeong", "pro", "jdk", "java");
names.stream();
//배열로 스트림 생성
Double[] dArray = {3.1, 3.2, 3.3};
Arrays.stream(dArray);
// 스트림 직접 생성
Stream<Integer> str = Stream.of(1,2);
2. 가공하기
filter
- 스트림 내 요소들을 하나씩 평가해 걸러내는 작업
- ex: "b"가 포함되어 있는 요소들만 스트림 형태로 반환
List<String> names = Arrays.asList("abc","bcd","cde","def");
Stream<String> st = names.stream().filter(x -> x.contains("b"));
map
- 스트림 내 요소들을 하나씩 연산
- ex: 스트림 내 String의 toUpperCase 메소드 실행기술 중 하나
List<String> names = Arrays.asList("a","b","c","d");
Stream<String> st = names.stream().map(String::toUpperCase);
sorted
- 요소들 정렬
- 디폴트: 오름차순
List<String> lang = Arrays.asList("Java", "Scala", "Groovy", "Python", "Go", "Swift");
lang = lang.stream()
.sorted() // 오름차순
.collect(Collectors.toList());
lang = lang.stream()
.sorted(Comparator.reverseOrder()) // 내림차순
.collect(Collectors.toList());
lang.stream()
.sorted(Comparator.comparingInt(String::length)) // 글자수 기준, 오름차순
.collect(Collectors.toList());
lang.stream()
.sorted((s1, s2) -> s2.length() - s1.length()) // 글자수 기준, 내림차순
.collect(Collectors.toList());
peek
- 스트림 내 각 요소들로 특정 연산 수행
- 특정 결과 반환 X
- ex: 계산 과정 보고싶은 경우
int sum = IntStream.of(1, 3, 5, 7, 9)
.peek(System.out::println)
.sum();
3. 결과 만들기
count, min, max, sum
- 요소들에 대한 개수, 최소값, 최대값, 합계
- ex: 값이 1인 요소의 개수
List<Integer> ages = Arrays.asList(1, 2, 3);
ages.stream().map(x->x==1).count();
reduce
- 누적된 값을 계산
- ex: 요소들의 합 구하기. x+y 결과는 다음 스트림의 x, 다음 요소는 y가 되어 계속 누적된다.
List<Integer> ages = Arrays.asList(1, 2, 3);
ages.stream().reduce((x,y) -> x+y).get(); // 1+2+3 = 6
ages.stream().reduce((a,b) -> { return Integer.sum(a,b); });
ages.stream().reduce(0, Integer::sum); // 0은 초기값. 10으로 할 경우 10+1+2+3=16이 됨
forEach
- 요소를 돌며 실행되는 최종 작업
- peek과 유사하지만 peek은 중간 작업임
names.stream().forEach(System.out::println);
collect
- Collector 타입의 인자를 받아서 처리
- 예제 외에도 Collectors를 활용한 예는 많지만 생략하겠다. (포스팅 아래에 참조1 링크에서 자세히 확인 가능)
productList.stream()
.map(Product::getName)
.collect(Collectors.toList()); // 리스트로 결과 가져오기
productList.stream()
.map(Product::getName)
.collect(Collectors.joining()); // 스트림 작업 결과를 하나의 String으로 이어붙이기
productList.stream()
.map(Product::getName)
.collect(Collectors.joining(", ", "<", ">")); //<요소1, 요소2, 요소3>
productList.stream()
.collect(Collectors.averagingInt(Product::getAmount)); // 숫자 값의 평균
noneMatch, anyMatch, allMatch
- noneMatch: 모든 요소들이 조건 불만족 하는지
- anyMatch : 하나라도 조건 만족하는지
- allMatch : 모든 요소들이 조건 만족하는지
- return boolean값
boolean anyMatch = names.stream()
.anyMatch(name -> name.contains("a"));
스트림 동작 순서
대략적인 스트림 연산들을 살펴보았으니 이제 동작 순서를 살펴보자.
다음 코드에 대해 출력 결과를 생각해보자.
Arrays.stream(new String[]{"c", "python", "java"})
.filter(word -> {
System.out.println("Call filter method: " + word);
return word.length() > 3;
})
.map(word -> {
System.out.println("Call map method: " + word);
return word.substring(0, 3);
}).findFirst();
결론부터 말하자면 출력 결과는 다음과 같고, 연산 결과는 "pyt"이다.
Call filter method: c Call filter method: python Call map method: python |
이제 스트림의 동작 과정을 유추해보자.
메소드\데이터 | c | python | java |
filter() | ㅇ | ㅇ | |
map() | ㅇ | ||
findFirst() | ㅇ |
- 배열의 첫 번째 요소인 "c"는 filter()를 거친다.
- "c"는 length()가 3을 넘지 않아서 map()을 거치지 않는다.
- 배열의 두 번째 요소인 "python"은 filter()를 거친다.
- "python"은 map()을 거친다.
- "python"은 findFirst()를 거친다.
- findFirst()는 조건에 맞는 하나의 결과를 찾았기 때문에 다음 요소인 "java"에 대해서는 수행하지 않는다.
filter()에서 모든 요소를 거친 후 다음 연산을 수행하는 방식이 아니라,
요소 하나하나에 대해 filter().map().findFirst()를 거치는 방식이다.
(표로 따지면 진행 방향이 →가 아니라 ↓)
스트림을 사용한다고 무조건적으로 성능 개선이 되는 것이 아니라 상황에 따라 알맞게, 순서를 고려하여 코딩하는 것이 바람직하다.
참조
(1) futurecreator.github.io/2018/08/26/java-8-streams/
(3) madplay.github.io/post/mistakes-when-using-java-streams
반응형
'Develop > Java' 카테고리의 다른 글
[Java] MessageFormat (0) | 2021.03.22 |
---|---|
[Java, Spring] 파일 다운로드 (0) | 2021.03.22 |
[Jackson] com.fasterxml.jackson.core.JsonParseException 에러 (0) | 2021.03.09 |
[Ant] Unable to find a javac compiler 에러 (0) | 2021.03.05 |
[Ant] Unable to locate tools.jar. Expected to find it ... 에러 (0) | 2021.03.02 |