JAVA

[Java] java8 stream

퉁그리 2021. 12. 17. 00:54

java8부터 지원이 된 stream은 람다함수형식으로 간결하고 직관적으로 요소들을 처리가 가능한 기능이다.

이러한 stream을 이용해 for문 등 직관적이지 않은 처리들을 깔끔하게 처리할 수 있다.

 

Stream의 구조

stream의 구조는 크게 세가지로 볼 수 있다.

1. stream의 생성

2. 중개 연산

3. 최종 연산

 

세가지로 구성되있으며, 중개연산은 연산결과를 stream형태로 반환하기 때문에 연속적으로 사용할 수 있다.

대략적인 구조는

데이터소스객체집합.stream생성().중개연산().최종연산();

이다.

 

Stream 생성

스트림 api는 다음과 같은 다양한 종류의 소스들에 사용할 수 있다.

 

1. 컬렉션

2. 배열

3. 가변 매개변수

4. 지정된 범위의 연속된 정수

5. 특정 타입의 난수

6. 람다 표현식

7. 파일

8. 빈 스트림

 

중개 연산

중개 연산은 stream을 받아 stream형식으로 리턴하기 때문에 중개 연산을 연속으로 사용할 수 있다.

stream의 중개연산은 필터-맵(filter-map)기반의 api를 사용함으로서 지연(lazy) 연산을 통해 성능을 최적화할 수 있다.

대표적인 중개 연산들은

1. stream 필터링 : filter(), distinct()

2. stream 변환 : map(), flatMap()

3. stream 제한 : limit(), skip()

4. stream 정렬 : sorted()

5. stream 연산 결과 확인 : peek()

 

예시

ArrayList<Int> list = new ArrayList<>(Arrays.asList(1, 5, 3, 5, 4, 5));

//distinct 중복 제거
list.stream().distinct().forEach(System.out::print);
// 1534

//filter 해당하는것만 필터링
list.stream().filter(n -> n % 2 != 0).forEach(e -> System.out.print(e + " "));
// 1 5 3 5 5


ArrayList<String> list = new ArrayList<>(Arrays.asList("Drogba", "Essien", "Terry", "Lampard"));

//map 스트림의 요소들을 인수로 전달하여, 반환값들로 새로운 스트림을 변환
list.stream().map(String::toUpperCase()).forEach(System.out::println);
// DROGBA ESSIEN TERRY LAMPARD

ArrayList<String> list = new ArrayList<>(Arrays.asList(
    "I love Drogba", "I want to be Essien", "Terry is nice guy", "Lampard is best coach"));

//flatmap 이차배열이나, 여럿문자열이 저장된 스트림을 단일스트림으로 변환
list.stream().map(String::toUpperCase()).forEach(System.out::print);
//IloveDrogbaIwanttobeEssienTerryisnoceguyLampardisbestcoach


ArrayList<Int> list = new ArrayList<>(Arrays.asList(1, 5, 3, 5, 4, 5));

//limit 앞요소 제거
list.stream().skip(2).forEach(System.out::print);
// 3545

//filter 뒷요소 제거
list.stream().limit(3).forEach(System.out::print);
// 153

 

최종 연산

최종 연산은 앞서 중개 연산을 통해 만들어진 stream에 있는 요소들에 대해 마지막으로 각 요소를 소모하며 최종 결과를 보여준다. 즉 지연(lazy)되었던 모든 중개연산들이 최종 연산 시에 모두 수행된다. 이렇게 최종 연산시에는 모든 요소를 소모한 해당 stream은 더이상 사용할수없다.

대표적인 최종연산 메소드들은 다음과 같다.

1. 요소의 출력 : forEach()

2. 요소의 소모 : reduce()

3. 요소의 검색 : findFirst(), findAny()

4. 요소의 검사 : anyMatch(), allMatch(), noneMatch()

5. 요소의 통계 : count(), min(), max()

6. 요소의 연산 : sum(), average()

7. 요소의 수집 : collet()

 

예시

 

//findFirst(), findAny()  output 형식 Optional
ArrayList<String> list = new ArrayList<>(Arrays.asList("넷", "둘", "하나", "셋"));

Optional<String> first = list.stream().filter(s -> s.stratsWith("넷")).findFirst();
//first.get() -> 넷

Optional<String> any = list.stream().filter(s -> s.stratsWith("넷")).findAny();
//any.get() -> 넷
//findFirst, findAny 차이 -> findAny는 병렬처리 첫번째값 리턴으로 매 리턴마다 값이 다를 수 있다.


//allMatch(), anyMatch(), noneMatch() output 형식 boolean
ArrayList<Int> list = new ArrayList<>(Arrays.asList(3, 7, 5, 4, 4, 2, 9));


boolean result = list.stream().allMatch(a -> a%2 == 0);
//false 모든값이 해당하면 true

boolean result = list.stream().anyMatch(a -> a%2 == 0);
//true 해당값 하나라도 있으면 true

boolean result = list.stream().noneMatch(a -> a%6 == 0);
// true 모든값이 해당되지 않으면 true


//collect()
ArrayList<Int> list = new ArrayList<>(Arrays.asList(3, 7, 5, 4, 4, 2, 9));
List<String> list = list.stream().filter(n -> n % 2 ! = 0).collect(Collectors.toList()); // 스트림을 리스트로 변환

//Collectors 클래스의 partitioningBy()
ArrayList<String> list = new ArrayList<>(Arrays.asList("넷", "둘", "하나", "셋"));
//해당 stream의 각 요소별 글자 수에 따라 홀수와 짝수로 나누어 저장

Map<Boolean, List<String>> partition = list.stream().collect(Collectors.partitioningBy(s -> (s.length() % 2) == 0));
List<String> oddLengthList = patition.get(false);//넷, 둘, 셋
List<String> evenLengthList = patition.get(true);//하나

 

 

 

출처 : [Java] Java 8 Stream이란? (tistory.com)