빡코

[Java] 스트림 API 본문

카테고리 없음

[Java] 스트림 API

chris.djang 2020. 2. 4. 19:13

Stream은 자바 8부터 추가된 기능으로 "컬렉션, 배열등의 저장 요소를 하나씩 참조하며 함수형 인터페이스(람다식)를 적용하며 반복적으로 처리할 수 있도록 해주는 기능"이다
즉, 불필요한 코딩(for, if 문법)을 걷어낼 수 있고 직관적이기 때문에 가독성이 좋아진다.

 

package coding_test;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Test3 {

    public static void main(String[] args) {

        List<String> names = Arrays.asList("jeong","pro","jdk","java");
        long count = 0;

        //기존 for문을 이용
        for(String name: names){
            if(name.contains("o")){
                count++;
            }
        }
        System.out.println("count: "+ count);

        //스트림 이용한 방식
        count = 0;
        count = names.stream().filter(x ->x.contains("o")).count();//fitler: 조건엔 맞는것만 거른다
        System.out.println("count2: "+count);

        //map을 이용
        names.parallelStream()
                .map((x) ->{return x.concat("s");})
                .forEach(x-> System.out.println(x));
        //map은 스트림의 각 요소를 연산하는데 쓰인다.
        //위의 경우는 각 문자열(요소)akek 뒤에 "s"를 붙인다.
        //*concat 함수: 문자열과 문자열을 합친 함수를 리턴한다.

        List<Integer> nums = Arrays.asList(1,2,3,4,5);
        nums.parallelStream()
                .map((x) ->{return x*2;}) //각요소에 연산 적용
                .forEach(x -> System.out.println(x));

        //Limit
        List<Integer> ages = Arrays.asList(1,2,3,4,5,6,7,8,9);
        ages.stream().filter(x -> x>3).limit(3) //스트림갯수를 3으로 제한
                .forEach(x -> System.out.printf("%d,",x));

        List<Integer> nums2= Arrays.asList(4,4,2,3,1,2);
        nums2.stream()
                .sorted() //정렬
                .distinct() //중복제거
                .forEach(x -> System.out.println(x));

        //skip: .skip(3): 처음 3개의 요소는 제외하고 나머지 요소들로 새로운 트림 만든다
        List<Integer> nums3 = Arrays.asList(1,2,3,4,5,6,7,8,9);
        nums3.stream().skip(3)
                .forEach(x -> System.out.println(x));


        //reduce: 아래에서 설명
        List<Integer> ages3 = new ArrayList<Integer>();
        ages3.add(1); ages3.add(2); ages3.add(3);
        System.out.println("값:"+ages3.stream()
                                        .reduce((b,c) -> b+c)
                                        .get());
    }

 }

 

Java8의 Stream reduction 사용 방법

System.out.println(Arrays.asList(1,2,3)
                          .stream().reduce(1,(a,b) -> {return a+b;}));
//결과값 7

reduce()의 param으로 (total, n) -> total + n가 전달되고, reduce는 a1, a2, a3, a4...의 stream을 a1 + a2 + a3 + a4...로 연산을 수행합니다. 첫번째로 total=a1, n=a2가 되고, 두번째로 total=(a1+a2), n=a3가 됩니다.

함수를 정의하지 않고 Integer::sum을 사용해도 위와 동일한 결과를 출력합니다.

Stream<Integer> numbers2 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Optional<Integer> sum2 = numbers2.reduce(Integer::sum);
        sum2.ifPresent(s -> System.out.println("sum2: " + s));
//결과값: sum2: 55

초기값 있는 Reduction

위와 동일한 동작을 하지만 초기값을 지정해줄 수 있습니다. 첫번째 param으로 초기값을 넘겨주면 됩니다. 초기값이 없는 위와 유사하게 '10 + 1 + 2 + ... 10'으로 연산됩니다.

Stream<Integer> numbers3 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum3 = numbers3.reduce(10, (total, n) -> total + n);
System.out.println("sum3: " + sum3);
//sum3: 65

병렬처리 & Reduction

parallel()을 사용하면 병렬처리로 연산을 수행할 수 있습니다. 순차적으로 연산을 수행하지 않고 여러개의 작업을 병렬로 처리합니다. (1 + 2) + (3 + 4) + ... + (9 + 10)처럼 병렬적으로 처리됩니다.

Stream<Integer> numbers4 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum4 = numbers4.parallel().reduce(0, (total, n) -> total + n);
System.out.println("sum4: " + sum4);
//sum4: 55

하지만 -(마이너스) 연산인 경우 병렬처리는 순차처리와 결과가 다릅니다. 아래 코드를 보면 결과가 -55가 아니라 -5가 됩니다. (1 - 2) - (3 - 4) - ... - (9 - 10)처럼 연산의 순서가 어떻게 되냐에 따라서 결과가 순차처리와 다르게 됩니다.

Stream<Integer> numbers5 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum5 = numbers5.parallel().reduce(0, (total, n) -> total - n);
System.out.println("sum5: " + sum5);
//sum5: -5

순서 있는 병렬처리 Reduction

병렬처리에서 연산 순서에 따라 발생하는 문제를 해결하기 위해 다음과 같이 다른 규칙을 추가할 수 있습니다. param으로 (total1, total2) -> total1 + total2를 추가하였는데 병렬처리된 결과의 관계를 나타냅니다. 첫번째 연산과 두번째 연산은 합해야 한다는 규칙을 정의하여, 연산결과가 순차처리와 동일하게 됩니다.

Stream<Integer> numbers6 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum6 = numbers6.reduce(0,
(total, n) -> total - n,
(total1, total2) -> total1 + total2);
System.out.println("sum6: " + sum6);
//sum6: -55

 

 

 

 

 

참조

https://codechacha.com/ko/java8-stream-reduction/

https://www.baeldung.com/java-stream-reduce //원문

https://wraithkim.wordpress.com/2017/04/13/java-8-%EC%8A%A4%ED%8A%B8%EB%A6%BC-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC/

https://jeong-pro.tistory.com/165

http://iloveulhj.github.io/posts/java/java-stream-api.html