본문 바로가기
GD's IT Lectures : 기초부터 시리즈/자바(JAVA) 기초부터 ~

[자바(JAVA)] 스트림 API

by GDNGY 2023. 4. 28.

17. 스트림 API

스트림(Stream) API는 자바 8에서 추가된 기능으로, 데이터를 처리하는 데 도움이 되는 함수형 프로그래밍 도구입니다. 스트림 API를 사용하면 복잡한 연산을 쉽게 처리할 수 있으며, 코드의 가독성을 향상할 수 있습니다. 

 

17.1. 스트림 API 개요

스트림은 데이터 소스에서 데이터를 읽고, 중간 연산과 최종 연산을 통해 결과를 생성합니다. 스트림은 함수형 프로그래밍과 람다 표현식을 활용하여 간결하고 가독성 있는 코드 작성을 지원하며, 병렬 처리를 통한 성능 향상도 지원합니다.

 

17.2. 스트림 생성

스트림은 다양한 데이터 소스로부터 생성할 수 있습니다. 주로 컬렉션, 배열, I/O 채널, 생성자 등을 통해 스트림을 생성합니다.

// 컬렉션에서 스트림 생성
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();

// 배열에서 스트림 생성
String[] array = {"a", "b", "c"};
Stream<String> streamFromArray = Arrays.stream(array);

// 스트림 생성자를 사용한 스트림 생성
Stream<Integer> intStream = Stream.of(1, 2, 3);

 

17.3. 스트림 연산 (중간 연산, 최종 연산)

스트림 연산은 데이터 소스에 대한 변환과 처리를 수행하며, 이를 통해 개발자는 데이터 처리 작업을 더 효율적이고 간결하게 작성할 수 있습니다. 스트림 연산은 크게 중간 연산(intermediate operations)과 최종 연산(terminal operations)으로 구분됩니다.

 

●  중간 연산(Intermediate operations) : 중간 연산은 스트림을 변환하여 새로운 스트림을 생성합니다. 중간 연산은 또 다른 중간 연산이나 최종 연산을 스트림에 적용하기 전까지는 실제로 수행되지 않는 지연 평가(lazy evaluation) 방식을 사용합니다. 주요 중간 연산에는 filter, map, flatMap, distinct, sorted, peek 등이 있습니다.

List<String> names = Arrays.asList("Alice", "Bob", "Cindy", "David", "Eva");

// 필터링
Stream<String> filtered = names.stream().filter(name -> name.length() > 3);

// 매핑
Stream<Integer> lengths = names.stream().map(String::length);

// 정렬
Stream<String> sorted = names.stream().sorted();

●  최종 연산(Terminal operations): 최종 연산은 스트림을 소비하여 결과를 생성하거나 더 이상 스트림을 사용할 수 없게 합니다. 최종 연산은 스트림의 모든 중간 연산을 실제로 수행하고, 최종 결과를 반환합니다. 주요 최종 연산에는 forEach, toArray, reduce, collect, min, max, count, anyMatch, allMatch, noneMatch 등이 있습니다.

List<String> names = Arrays.asList("Alice", "Bob", "Cindy", "David", "Eva");

// forEach: 모든 요소에 대한 작업 수행
names.stream().forEach(System.out::println);

// toArray: 스트림을 배열로 변환
String[] nameArray = names.stream().toArray(String[]::new);

// reduce: 스트림 요소를 줄여 하나 결과 생성 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// reduce를 사용해 합계 구하기 Optional<Integer> sum = numbers.stream().reduce(Integer::sum);
// collect: 스트림 요소를 컬렉션 또는 다른 자료 구조로 변환 List<String> uppercasedNames = names.stream().map(String::toUpperCase).collect(Collectors.toList());

 

17.4. 병렬 스트림

병렬 스트림(Parallel Stream)은 스트림 연산을 여러 스레드로 분할하여 동시에 처리하는 기능입니다. 병렬 스트림을 사용하면 멀티코어 프로세서의 성능을 활용하여 데이터 처리 속도를 향상시킬 수 있습니다. 그러나 동시성 문제와 관련된 주의 사항이 있으므로, 병렬 스트림 사용에 신중해야 합니다.

 

  • 병렬 스트림 생성

기존의 스트림을 병렬 스트림으로 변환하려면 parallel() 메소드를 사용하면 됩니다. 또한, 컬렉션 인스턴스의 parallelStream() 메서드를 사용하여 병렬 스트림을 직접 생성할 수도 있습니다.

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

// 기존 스트림을 병렬 스트림으로 변환
Stream<Integer> parallelStream = numbers.stream().parallel();

// 컬렉션 인스턴스의 parallelStream() 메소드 사용
Stream<Integer> parallelStreamFromCollection = numbers.parallelStream();

- 병렬 스트림의 주의점

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

 

  1. 상태 변경이 있는 연산: 병렬 스트림에서는 여러 스레드가 동시에 작업을 수행하므로, 상태 변경이 있는 연산은 동시성 문제를 일으킬 수 있습니다. 이러한 경우, 상태 변경이 없는 연산을 사용하거나 동기화 처리를 해야 합니다.
  2. 순서 보장: 병렬 스트림에서는 연산 순서가 보장되지 않습니다. 연산의 순서가 중요한 경우, 병렬 스트림을 사용하지 않는 것이 좋습니다.
  3. 병렬 스트림 사용 시점: 모든 작업에 병렬 스트림을 사용하는 것이 항상 좋지는 않습니다
반응형

댓글