티스토리 뷰

Java

[Stream API] 스트림이란?

GOMSHIKI 2023. 10. 28. 15:51

스트림(Stream)

 

1. 스트림이란?

과거 Collection이나 Iterator와 같은 인터페이스를 이용해서 컬렉션을 다루는 방식을 표준화했지만, 각 Collection Class에는 같은 기능의 메서드를 중복해서 정의되어있음.

ex) List 정렬 시 Collections.sort()를 사용해야하고, Array 정렬 시 Arrays.sort()를 사용해야함

이를 해결하고 만든 것이 '스트림(Stream)'!! 

스트림은 데이터 소스를 추상화하고, 데이터를 다루는데 사용되는 메서드를 정의해 놓음. 

 

* 스트림의 장점

1) 데이터 소스가 무엇이던 같은 방식으로 다룰 수 있게됨

2) 코드의 재사용성이 높아짐

 

*스트림을 사용하지 않는 코드

public class StreamStudy {

    public static void main(String[] args) {

        /**
         * Array 와 List 정의
         */
        String[] strArr = {"aaa", "ddd", "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);
        }



    }
}

 

 

* 스트림을 이용한 코드

public class StreamStudy {

    public static void main(String[] args) {

        /**
         * Array 와 List 정의
         */
        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);


    }
}

 

 

1.1 스트림은 휘발성!

스트림을 한번 사용하면 이후 재사용 불가!!

strStream1.sorted().forEach(System.out::println);
int numOfStr = strStream1.count(); // 에러발생. 이미 스트림이 닫힘!!

 

 

1.2  스트림은 작업을 내부 반복으로 처리

void forEach(Consumer<? super T> action) {
	Object.requireNonNull(action); // 매개변수 Null 확인
    
    for(T t : src) {			// 내부 반복
    	action.accept(t);
    }
}

 

 

 

1.3  스트림 연산

중간 연산 : 연산 결과가 스트림인 연산. 스트림에 연속해서 중간 연산 가능!!
최종 연산 : 연산 결과가 스트림이 아닌 연산. 스트림의 요소를 소모하므로 한번만 가능!!
// dintinct() : 중간연산
// limit(5) : 중간연산
// sorted() : 중간연산
// forEach() : 최종연산
stream.distinct().limit(5).sorted().forEach(System.out::println)

 

* 하나씩 뜯어보기!!

public static void main(String[] args) {


    String[] strArr = {"dd", "aaa", "CC", "cc", "bb"};

    Stream<String> stream = Stream.of(strArr); // 문자열 배열이 소스인 스트림
    Stream<String> upperStrStream = stream.map(word -> word.toUpperCase()); // 대문자로 변환(중간 연산)
    Stream<String> filteredStream = upperStrStream.filter(str -> str.contains("CC")); // 필터링(중간 연산)
    Stream<String> distinctedStream = filteredStream.distinct(); //중복제거(중간 연산)
    Stream<String> sortedStream = distinctedStream.sorted(); // 정렬(중간 연산)
    sortedStream.forEach(System.out::println); // 출력(최종 연산)

}

 

* 중간연산과 최종연산 메서드 정리

※ 주로 사용하는 메서드 : map(), flatMap(), reduce(), collect()

중간연산 설명
Stream<T> distinct() 중복 제거
Stream<T> filter(Predicate<T> predicate) 조건에 안 맞는 요소 제외
Stream<T> limit(long maxSize) maxSize 만큼만 가져옴
Stream<T> skip(long n) n 만큼 건너뜀
Stream<T> sorted()
Stream<T> sorted(Comparator<T> comparator)
정렬
* map()
Stream<R>       map( Function<T,R> mapper )
DoubleStream  mapToDouble( toDoubleFunction<T> mapper )
IntStream          mapToInt( toIntFunction<T> mapper )
LongStream      mapToLong( ToLongFunction<T> mapper )

* flatMap()
Stream<R>       flatMap( Function<T, Stream<R>> mapper )
DoubleStream  flatMapToDouble( Function<T, DoubleStream> mapper )
IntStream          flatMapToInt( Function<T, IntStream> mapper)
LongStream      flatMapToLong( Function<T, LongStream> mapper)
스트림 요소 반환

 

최종 연산 설명
void forEach(Consumer<? super T> action)
void forEachOrdered(Consumer<? super T> action)
각 요소에 지정된 작업 수행
long count() 스트림 요소 개수 반환
Optional<T> max(Comparator<? super T> comparator)
Optional<T> min(Comparator<? super T> comparator)
스트림의 최대값/최소값을 반환
Optional<T> findAny() // 아무거나 하나 반환
Optional<T> findFirst() // 첫 번째 요소 반환
요소 하나 반환
boolean allMatch(Predicate<T> p) // 모두 만족 시 true
boolean anyMatch(Predicate<T> p) // 하나라도 만족 시 true
boolean nonMatch(Predicate<T> p) //모두 불만족 시 true
주어진 조건의 만족 여부 확인
Object[] toArray()
A[]          toArray(IntFunction<A[] generator>
모든 요소를 배열(Array)로 반환
* reduce()
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
U reduce(U identity, BiFunction<U,T,U> accumulator, BinaryOperator<U> combiner)
스트림 요소를 하나씩 줄여가며(Reducing) 계산
* collect()
R collect(Collector<T,A,R> collector)

R collect(Supplier<R> supplier, BiConsumer<R,T> accumulator, BiConsumer<R,R> combiner)
스트림 요소를 수집.
요소를 그룹화 or 분할한 결과를 컬렉션에 담아 반환

 

 

 

1.4 지연된 연산

스트림 연산은 최종 연산이 수행되기 전까지 중간 연산이 수행되지 않음.

 

 

1.5 Stream<Integer> vs IntStream

스트림에서 오토박싱 & 언박싱으로 인한 비효율을 줄이기 위해 기본형 스트림(IntStream, LongStream, DoubleStream)을 제공

일반적으로, Stream<Integer> 보다 IntStream 사용이 더 효율적!!

 

 

1.6 병렬 스트림

스트림의 장점 중 하나는 병렬처리가 쉽다는 것인데, 병렬 스트림은 내부적으로 for&join프레임워크를 이용해 자동적으로 병렬연사을 수행

사용은 스트림에 parallel() 메서드를 호출하면 되며, 반대로 병렬처리하지 않게 하려면 sequential()을 호출하면 됨.

(단, 모든 스트림은 default로 병렬 스트림이 아니므로 sequential()을 호출할 필요 없음)

int sum = strStream.parallel() // 병렬 스트림으로 전환
                    .mapToInt(s -> s.length())
                    .sum();

 

'Java' 카테고리의 다른 글

[Stream API] 스트림 중간연산 (1/3)  (0) 2023.11.06
[Stream API] 스트림 만들기  (0) 2023.10.28
[Generices] 지네릭스  (0) 2023.10.24
[Java] 자바 언어의 특징  (0) 2023.07.24
[Java] BufferedReader / BufferedWriter 정리  (0) 2023.02.22
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함