Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
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
Tags
more
Archives
Today
Total
관리 메뉴

랩터

[Java] 스트림 - 스트림의 중간 연산 본문

공부/JAVA

[Java] 스트림 - 스트림의 중간 연산

raptorhs 2024. 7. 8. 12:41

전체적인 코드 구조를 파악해 보도록 하겠습니다.

 

 

중간연산에서 가장 많이 사용되는 필터링,매핑,정렬 등에 대해 살펴보겠습니다.

 

 

필터링(filter() , distinct() )

필터링은 이름 그대로 우리의 필요에 따라 조건에 맞는 데이터들만을 정제하는 역할을 하는 중간 연산자를 가리킵니다.

 

  • distinct() : Stream의 요소들에 중복된 데이터가 존재하는 경우, 중복을 제거하기 위해 사용합니다.
  • filter(): Stream에서 조건에 맞는 데이터만을 정제하여 더 작은 컬렉션을 만들어냅니다. filter()메서드에는 매개값으로 조건을 주고, 조건이 참이 되는 요소만 필터링합니다. 여기서 조건은 람다식을 사용하여 정의할 수 있습니다.

 

package Stream;

import java.util.Arrays;
import java.util.List;

public class FilteringExample {
    public static void main(String[] args) throws Exception{

        List<String> names = Arrays.asList("김코딩", "이자바", "박해커", "김코딩", "박해커");

        names.stream()
                .distinct() // 중복 제거
                .forEach(element -> System.out.println(element));

        System.out.println();

        names.stream()
                .filter(element -> element.startsWith("김"))//김씨 성을 가진 요소만 필터링
                .forEach(element -> System.out.println(element));

        System.out.println();

        names.stream()
                .distinct() // 중복제거
                .filter(element -> element.startsWith("김"))//김씨 성을 가진 요소만 필터링
                .forEach(element -> System.out.println(element));
    }
}

//출력값
김코딩
이자바
박해커

김코딩
김코딩

김코딩

 

첫 번째와 두 번째 스트림은 각각 독립적인 스트림입니다. 대표적인 최종 연산자인 forEach()로 첫 번째 스트림이 닫히고 난 후에 두 번째 스트림이 생성되어 새로운 연산을 수행하고 있습니다.

 

매핑(map())

매핑은 스트림 내 요소들에서 원하는 필드만 추출하거나 특정 형태로 변환할 때 사용하는 중간 연산자입니다.

위의 필터 메서드와 마찬가지로 값을 변환하기 위한 조건을 람다식으로 정의합니다.

 

package Stream;

import java.util.Arrays;
import java.util.List;

public class IntermediateOperationExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("kimcoding", "javalee", "hackerna", "luckyguy");
        names.stream()
                .map(element -> element.toUpperCase()) // 요소들을 하나씩 대문자로 변환
                .forEach(element -> System.out.println(element));
    }
}

//출력값
KIMCODING
JAVALEE
HACKERNA
LUCKYGUY

names안에 정의된 각 요소를 순회하면서 소문자 이름을 대문자로 변환한 값들이 담긴 스트림으로 반환하는 연산 과정코드입니다.

 

package Stream;

import java.util.Arrays;
import java.util.List;

public class IntermediateOperationExample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,3,6,9);

        //각 요소에 3을 곱한 값을 반환
        list.stream().map(number -> number * 3).forEach(System.out::println);
    }
}

 

map()과 flatMap()의 차이

 

package Stream;

import java.util.Arrays;
import java.util.List;

public class IntermediateOperationExample {
    public static void main(String[] args) {
        String[][] namesArray = new String[][]{{"박해커", "이자바"},{"김코딩","나박사"}};

        Arrays.stream(namesArray)
                .map(inner -> Arrays.stream(inner))
                .forEach(System.out::println);
    }
}
//출력값
java.util.stream.ReferencePipeline$Head@5b6f7412
java.util.stream.ReferencePipeline$Head@27973e9b

위의 메서드는 Stream<Stream<String>> 중첩 스트림을 반환하고 있기 때문에 원하는 결과값을 출력할 수 없습니다.

Stream<String>이 되어야 원하는 결과값을 얻을 수 있습니다.

 

// map 사용
        Arrays.stream(namesArray)
                .map(inner -> Arrays.stream(inner))
                .forEach(names -> names.forEach(System.out::println));

// 출력값
박해커
이자바
김코딩
나박사

 

forEach() 메서드 안의 람다식의 정의에서, 각 요소에 대하여 다시 forEach() 메서드를 출력함으로써 뎁스가 있는 요소들에 접근하여 이를 출력할 수 있습니다.

하지만 지금처럼 이중구조가 아닌 뎁스가 3중, 4중, 5중으로 깊어지는 경우는 어떨까요?

아마 코드를 작성하는 개발자 입장에서도 매우 번거롭고 작성된 코드 또한 가독성이 떨어질 것입니다.

이런 경우, 우리는 flatMap()을 활용할 수 있습니다.

// flatMap()
Arrays.stream(namesArray).flatMap(Arrays::stream).forEach(System.out::println);

// 출력값
박해커
이자바
김코딩
나박사

 

 

정렬(sorted())

sorted() 메서드는 이름처럼 정렬할 때 사용하는 중간 연산자입니다.

 

package Stream;

import java.util.Arrays;
import java.util.List;

public class IntermediateOperationExample {
    public static void main(String[] args) {
        List<String> animals = Arrays.asList("Tiger", "Lion", "Monkey", "Duck", "Horse", "Cow");

        //인자값 없는 sort() 호출
        animals.stream().sorted().forEach(System.out::println);
    }
}

 

괄호 안에 Comparator라는 인터페이스에 정의된 static 메서드와 디폴트 메서드를 사용하여 간편하게 정렬 작업을 수행할 수 있습니다. 괄호 안에 아무 값도 넣지 않은 상태로 호출하면 기본 정렬(오름차순)로 정렬됩니다.

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class IntermediateOperationExample {
    public static void main(String[] args) {

        List<String> animals = Arrays.asList("Tiger", "Lion", "Monkey", "Duck", "Horse", "Cow");

				// 인자값에 Comparator 인터페이스에 규정된 메서드 사용
        animals.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);

    }
}

// 출력값
Tiger
Monkey
Lion
Horse
Duck
Cow

 

 

기타

 

skip() - 스트림의 일부요소들을 건너뜁니다.

 

    import java.util.stream.IntStream;

    public class IntermediateOperationExample {
        public static void main(String[] args) {

            // 1~10 범위의 정수로 구성된 스트림 생성
            IntStream intStream = IntStream.rangeClosed(1, 10);

            // 앞의 5개의 숫자를 건너뛰고 숫자 6부터 출력
            intStream.skip(5).forEach(System.out::println);
        }
    }

    // 출력값
    6
    7
    8
    9
    10

 

limit() - 스트림의 일부를 자릅니다

 

    import java.util.stream.IntStream;

    public class IntermediateOperationExample {
        public static void main(String[] args) {

            // 1~10 범위의 정수로 구성된 스트림 생성
            IntStream intStream = IntStream.rangeClosed(1, 10);

            // 앞에서부터 5개의 숫자만 출력
            intStream.limit(5).forEach(System.out::println);
        }
    }

    // 출력값
    1
    2
    3
    4
    5

 

peek() - forEach()와 마찬가지로, 요소들을 순회하며 특정 작업을 수행합니다.

peek()는 중간연산자여서 여러번 사용 가능하지만,  forEach()는 최종연산자여서 단 한번만 사용가능합니다.

peek의 특성때문에 코드의 에러를 찾기위한 디버깅 용도로 종종 활용됩니다.

 

import java.util.stream.IntStream;

public class IntermediateOperationExample {
    public static void main(String[] args) {

        // 요소들을 사용하여 IntStream 생성
        IntStream intStream3 = IntStream.of(1, 2, 2, 3, 3, 4, 5, 5, 7, 7, 7, 8);

        // 짝수만 필터링하여 합계 구하기
        int sum = intStream3.filter(element -> element % 2 == 0)
                .peek(System.out::println)
                .sum();

        System.out.println("합계 = " + sum);
    }
}

// 출력값
2
2
4
8
합계 = 16

 

'공부 > JAVA' 카테고리의 다른 글

[Java] 스트림 - Optional Class  (0) 2024.07.09
[Java] 스트림 - 스트림의 최종 연산  (0) 2024.07.08
[Java] 스트림 - 스트림의 생성  (0) 2024.07.08
[Java] 스트림 - 핵심 개념과 특징  (0) 2024.07.08
[Java] 람다  (1) 2024.07.05