stream : map(), peek()

star_pooh·2024년 11월 27일
0

TIL

목록 보기
24/39
post-thumbnail

5주차 강의 과제 중에 map()을 사용하여 객체의 속성을 변경하는 문제가 있었는데, 주석으로 peek()를 사용한 코드도 있었다. 각각 어떤 특징이 있고 어떤 차이점이 있는지 알아보려고 한다.

map()과 peek()

map()peek() 모두 스트림 API에서 사용하는 메소드로, 주로 스트림 내 데이터를 처리할 때 사용된다.

주요 차이점 비교

특징map()peek()
목적스트림의 요소를 변환하여 새로운 스트림 생성스트림의 각 요소를 확인하거나 부작용(Side Effect)을 처리
입출력 관계입력 요소를 변환하여 새로운 요소를 출력입력 요소와 출력 요소가 동일
변환 여부데이터를 변환(Transform)하여 새로운 객체 또는 값으로 생성데이터를 변경하지 않음 (단, 부작용(Side Effect)으로 기존 객체를 수정 가능)
주요 사용 사례데이터 매핑(예: 객체 속성 변환, 값 연산 등)디버깅, 로깅, 또는 기존 객체 수정
실행 시점최종 연산이 호출될 때 실행최종 연산이 호출될 때 실행
사용 제한새로운 스트림 요소가 필요할 때만 사용주로 부작용(Side Effect) 처리가 필요하거나 확인 작업이 있을 때 사용
반환 스트림의 타입변환된 타입의 새로운 스트림입력과 동일한 타입의 스트림
주요 메서드 체이닝 목적데이터 변경 후 다음 스트림 연산에 활용데이터 확인 또는 부작용 후 다음 연산으로 그대로 전달

map()의 사용 예제

List<String> names = List.of("Alice", "Bob", "Charlie");
List<Integer> nameLengths = names.stream()
    .map(String::length)
    .collect(Collectors.toList());

System.out.println(nameLengths); // [5, 3, 7]


#### peek()의 사용 예제
>
```java
// 디버깅, 로깅
List<String> names = List.of("Alice", "Bob", "Charlie");
names.stream()
    .peek(name -> System.out.println("Processing: " + name))
    .map(String::toUpperCase)
    .collect(Collectors.toList());
>
// Processing: Alice
// Processing: Bob
// Processing: Charlie
// 기존 객체 수정
List<Book> discountedBookList =
    bookList.stream()
        .filter(book -> book.getCategory().equals("IT"))
        .peek(book -> book.setPrice(book.getPrice() * 0.6))
        .toList();

부작용(Side Effect)이란?

  • 함수형 프로그래밍 또는 스트림 처리에서 함수가 입력 값을 처리하는 과정에서 외부 상태를 변경하거나 예상치 못한 영향을 미치는 행동을 의미한다.
  • 순수 함수의 특징인 입력 값에 따른 결과 값의 일관성을 깨트릴 수 있다.
  • 함수 실행 시 다음과 같은 작업이 발생하는 것을 의미한다.
    • 외부 변수 수정 (ex. 전역 변수 변경)
    • 객체의 내부 상태 변경 (ex. 필드 값 수정)
    • IO 작업 수행 (ex. 파일 쓰기, 콘솔 출력)
    • 예외 발생 (ex. NullPointerException)

부작용이 문제가 되는 이유

  • 디버깅의 어려움
    • 코드의 흐름이 복잡해지고, 예상치 못한 상태 변경이 디버깅을 어렵게 만든다.
  • 재사용성 저하
    • 부작용이 있는 함수는 다른 환경에서 사용할 때 의도하지 않은 결과를 초래할 수 있다.
  • 병렬 처리의 문제
    - 스트림을 병렬로 처리할 경우, 부작용이 있는 함수는 동시성 문제를 일으킬 수 있다.

    💡 동시성 문제란?
    여러 스레드나 작업이 동시에 실행되면서, 동일한 자원에 접근하거나 수정하려고 할 때 발생하는 비정상적인 동작

부작용을 줄이는 방법

  • 객체 불변성 유지
    • 객체를 수정하는 것이 아닌, 변경이 필요한 경우 새 객체를 반환한다.
bookList.stream()
    .map(book -> new Book(book.getTitle(), book.getPrice() * 0.8))
    .toList();
  • peek()의 역할 최소화
    • peek()는 주로 디버깅 및 로깅 용도로 사용하고, 상태 변경에는 사용하지 않는 것이 권장된다.
  • 순수 함수 사용
    • 외부 상태를 변경하지 않는 함수 설계를 지향한다.

부작용이 필요한 상황

  • 로깅 및 디버깅
  • IO 작업
    • 파일을 저장하거나 데이터를 네트워크에 전송하는 등 외부 상태 변경이 필수적인 경우에 필요하다.

0개의 댓글

관련 채용 정보