[JAVA] Stream에 대해 알아보자. (2)

Lord·2024년 3월 15일

JAVA

목록 보기
4/7
post-thumbnail

저번 시간에는 자바 스트림을 사용하는 방법에 대해 자세하게 다루어 보았다. 그렇다면 이제 스트림을 사용할 줄 알기 때문에 어떻게 스트림을 잘 사용할까에 대해 알아볼 것이다.

병렬 스트림

자바 병렬 스트림(Parallel Stream)은 Java 8부터 도입된 기능 중 하나로, 스트림 API의 확장된 기능이다. 병렬 스트림을 사용하면 멀티코어 프로세서를 활용하여 대량의 데이터를 병렬적으로 처리할 수 있다. 이를 통해 성능을 향상시킬 수 있다. 이제 자세히 알아보도록 하자.

병렬 스트림의 생성

병렬 스트림을 생성하는 방법은 매우 간단하다. 기존의 스트림을 생성한 후에 parallel() 메서드를 호출하면 된다.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Stream<Integer> parallelStream = numbers.parallelStream();

위의 코드에서 parallelStream() 메서드를 호출함으로써 병렬 스트림을 생성한다.

병렬 스트림의 내부 작동

병렬 스트림은 내부적으로 Fork/Join 프레임워크를 사용하여 작업을 병렬로 처리한다. 이 프레임워크는 작업을 작은 작업으로 나누어 여러 스레드에 할당하고, 그 결과를 모아 최종 결과를 반환한다. 이 과정에서 병렬 스트림은 스레드 풀을 사용하여 작업을 분배하고 관리한다.

주의할 점

병렬 스트림을 사용할 때 주의해야 할 몇 가지 사항이 있다.

  1. 순서 보존: 병렬 처리는 작업의 순서를 보장하지 않을 수 있다. 따라서 연산의 결과가 순서에 의존하는 경우 주의해야 한다.
  2. 동시성 문제: 병렬로 실행되는 작업 간의 동기화에 주의해야 한다. 공유 상태에 대한 동시성 문제를 해결하기 위해 스레드 안전한 자료구조나 동기화 메커니즘을 사용해야 한다.

성능 최적화

병렬 스트림의 성능을 최적화하기 위해서는 다음과 같은 요소를 고려해야 한다.

  1. 스트림의 크기: 병렬 처리를 위해 분할된 작업의 크기가 중요하다. 따라서 데이터 크기에 따라 적절한 작업 분할을 고려해야 한다.
  2. 작업 병렬화: 병렬로 실행될 수 있는 작업을 식별하고 이를 병렬 스트림에 적용하여 성능을 향상시킬 수 있다.
  3. 스레드 풀 설정: Fork/Join 프레임워크의 스레드 풀 크기를 조정하여 최적의 성능을 얻을 수 있다.

예제

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

public class Main {
    public static void main(String[] args) {
        // 정수 리스트 생성
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        
        // 병렬 스트림을 이용하여 제곱 후 합계 계산
        int sumOfSquares = numbers.parallelStream()
                                 .mapToInt(n -> n * n)  // 각 요소를 제곱
                                 .sum();                // 제곱된 값들의 합계 계산

        System.out.println("제곱의 합: " + sumOfSquares);
    }
}

위의 코드에서는 parallelStream() 메서드를 호출하여 병렬 스트림을 생성한다. 그런 다음 mapToInt() 메서드를 사용하여 각 요소를 제곱하고, sum() 메서드를 사용하여 제곱된 값들의 합계를 계산한다. 이 작업은 병렬로 처리되며 멀티코어 프로세서를 활용하여 효율적으로 처리된다.

이 예시는 간단하지만 병렬 스트림이 어떻게 사용되는지를 보여준다. 요소가 더 많고 복잡한 연산을 수행하는 경우에도 비슷한 방식으로 병렬 스트림을 사용할 수 있다.

병렬 스트림의 활용

스프링 프레임워크에서의 활용

스프링 프레임워크에서도 스트림(Stream)을 활용하여 데이터 처리를 효율적으로 수행할 수 있다. 스프링 프레임워크는 스트림을 통해 데이터를 조회, 가공 및 변환하는 다양한 기능을 제공한다. 이를 통해 코드를 간결하게 작성하고 유지보수성을 높일 수 있다. 여기에는 주로 스프링 데이터 JPA와 스프링의 함수형 프로그래밍 지원이 포함된다.

1. 스프링 데이터 JPA에서의 스트림 활용

스프링 데이터 JPA는 데이터베이스와의 상호작용을 간소화하는 기능을 제공한다. 스프링 데이터 JPA에서는 Entity 객체에 대한 쿼리를 작성할 때 자바 8의 스트림을 활용할 수 있다. 이를 통해 데이터를 조회하고 처리할 때 보다 함수적이고 간결한 코드를 작성할 수 있다.

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.stream.Stream;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Stream<User> findAllByName(String name);
}

위의 코드에서는 UserRepository 인터페이스가 JpaRepository를 확장하고 있다. 여기에는 findAllByName() 메서드가 있는데, 이 메서드는 이름으로 사용자를 조회하는데, 이때 Stream을 반환한다. 이렇게 하면 사용자 데이터가 큰 경우에도 메모리를 효율적으로 사용할 수 있다.

2. 스프링 함수형 프로그래밍 지원

스프링 프레임워크는 함수형 프로그래밍을 지원하며, 이를 통해 스트림을 사용하여 데이터를 처리할 수 있다. 예를 들어, 스프링의 @Transactional 어노테이션을 사용하여 트랜잭션을 관리하고, flatMap()을 사용하여 데이터를 가공할 수 있다.

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Transactional(readOnly = true)
    public List<String> getUserNamesStartingWith(String prefix) {
        return userRepository.findAll().stream()
                             .filter(user -> user.getName().startsWith(prefix))
                             .map(User::getName)
                             .collect(Collectors.toList());
    }
}

위의 코드에서는 getUserNamesStartingWith() 메서드를 사용하여 이름이 주어진 접두사로 시작하는 사용자 이름 목록을 가져온다. 이때 userRepository.findAll()이 Stream을 반환하고, 이를 통해 스트림을 활용하여 데이터를 필터링하고 매핑한다.

이처럼 스프링 프레임워크에서는 함수형 프로그래밍의 장점을 활용하여 스트림을 다룰 수 있으며, 이를 통해 코드의 가독성과 유지보수성을 향상시킬 수 있다.

마무리

이렇게 병렬 스트림과 스트림의 활용에 대해 알아보았다. 다음 포스팅에서는 커스텀 콜렉터, 스트림의 내부 동작 메커니즘, 예외 처리에 대해 알아볼 것이다. 다음이 자바 스트림의 마지막편이 될 것 같다.

profile
다재다능한 Backend 개발자에 도전하는 개발자

0개의 댓글