java

[210118] java Stream (1) - stream 정의와 관련 메소드

hjk927 2021. 1. 18. 11:03

 

Stream은 java8에서 추가된 API이다. 데이터를 선언적으로 처리하고 특정 코드를 작성할 필요 없이 멀티 코어 아키텍처를 활용할 수 있도록 하기 위해 추가되었다. 

 

Stream의 특성은 아래와 같다.

  • Sequence of elements : stream은 순차적인 방식으로 특정 유형의 집합을 제공한다. 요소를 주문형으로 가져오고 처리하며, 요소를 저장하지는 않는다. 원본 데이터 구조를 변경하지도 않는다. 
  • Source : Stream으로 Collection, Array, 혹은 I/O 리소스를 사용할 수 있다. 
  • Aggregate operations : filter, map, limit, reduce, find, match 등의 메소드를 제공한다. 
  • Pipelining : 대부분의 Stream 함수가 처리 후에 자기자신을 return하면서, 파이프라인 형태로 구현할 수 있다. 
  • Automatic iterations : Stream 함수는 공급받은 요소에 대해서 내부적으로 이터레이터를 사용한다.  

 

 

관련 메소드


Empty Stream

stream을 사용하려면 stream 객체를 생성해야 한다. Stream.empty() 메소드를 사용해서 빈 stream 객체를 만들거나, Collection, Array의 경우는 내장 메소드를 사용해서 stream을 생성할 수 있다. 

        // 1. 빈 Stream 객체 생성
        Stream<Integer> stream1 = Stream.empty();

        // 2. Collection 객체에서 객체 생성
        List<Integer> list = new ArrayList<>(){};
        Stream<Integer> stream2 = list.stream();

        // 3. Array에서 stream 생성
        int[] array = new int[10];
        Stream<Integer> stream3 = Arrays.stream(array).boxed();

 

IntStream, LongStream, DoubleStream과 같은 인터페이스를 사용하면 자동으로 범위 안의 스트림 객체를 생성할 수 있다. 또, Random 클래스에 있는 ints, longs, doubles 메소드를 사용하면 랜덤의 수를 매개변수 개만큼 뽑아서 stream을 생성할 수 있다. 

        // 1. Random 객체 생성 
        Random random = new Random();
        
        // 2. int 형의 stream 생성
        // 2.1. IntStream.range 활용  
        IntStream intStream = IntStream.range(1, 5);
        // 2.2. random.ints() 활용
        intStream = random.ints(5);
        
        // 3. double 형의 stream 생성 
        DoubleStream doubleStream = random.doubles(3);
        doubleStream = random.doubles(5);
        

 

 

forEach

stream 내의 요소를 반복할 수 있다. 

        Random random = new Random();
        random.ints().limit(5).forEach(System.out::println);

        int[] arr = {1,2,3,4,5};
        Arrays.stream(arr).forEach( i -> System.out.println("i = " + i));

 

 

map 

stream 내의 요소 각각을 매핑하는 데 사용한다. 

        List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        
        List<Integer> squaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());
        squaresList.stream().forEach(i -> System.out.println("i = " + i));

 

 

distinct

stream 에 있는 요소 중 중복되는 요소를 제거한다. 

        List<Integer> list = Arrays.asList(1,4,2,3,3,5,1,4);

        list.stream().distinct().forEach(System.out::println);

distinct 사용 결과 리스트에 있는 중복 요소가 모두 제거된 것을 확인할 수 있다. 

 

 

 

filter 

주어진 기준에 따라서 요소를 걸러낼 때 사용한다. 

        List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");

        int count = (int) strings.stream().filter(string -> string.isEmpty()).count();
        System.out.println("count = " + count);

list에서 string이 null인 요소의 숫자를 세는 코드이다. 

 

 

limit 

stream의 크기를 제한할 때 사용한다. 

        Random random = new Random();
        random.ints().limit(5).forEach(System.out::println);

random.ints에서 5개만 추출해서 출력하였다. 

 

 

sorted 

stream을 정렬할 때 사용한다. 

        Random random = new Random();
        random.ints().limit(10).sorted().forEach(System.out::println);

 

 

 

Parallel Processing

병렬 처리를 위해서 사용된다. 

        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");

        long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
        System.out.println("count = " + count);

 

Collectors

stream 처리 결과를 합치는 데 사용한다. 처리 결과로 list나 string을 반환할 수 있다. 

 

        List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
        List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

        System.out.println("Filtered List: " + filtered);
        String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
        System.out.println("Merged String: " + mergedString);

Collectors.toList()로 실행 결과를 list로 반환하고, Collecttors.joining()을 사용해서 결과를 ', '으로 연결한 후 string으로 반환하였다. 

 

 

reduce

stream에서 연산을 수행해서 단일 결과를 생성할 수 있다. 

 

: Parameters

  • identity : 계산을 위한 초기값으로 stream이 비어있으면 디폴트 결과값이 된다. 
  • accumulator : 각 요소를 통합하기 위한 함수
  • combiner : 2개 값을 합치기 위한 함수로 병렬 스트림에서 작동한다. 
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        int result = numbers
                .stream()
                .reduce(0, (subtotal, element) -> subtotal + element);
        System.out.println("result = " + result);

reduce의 초기값은 0이며, 요소를 각각 더한 합을 반환한다. 결과로 21이 출력됨을 확인할 수 있다. 

 

 

 

-Reference 

www.tutorialspoint.com/java8/java8_streams.htm

www.baeldung.com/java-8-streams

futurecreator.github.io/2018/08/26/java-8-streams/

docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#reduce-T-java.util.function.BinaryOperator-