Java/Java 문법

[JAVA8] Stream API란 - fiter /map /of 사용방법

민돌v 2022. 5. 24. 01:01

 

 

JAVA Stream API

JAVA stream 과 stream API는 다릅니다.

java stream 은 java 에서 다루는, 입출력 흐름입니다.

 

우리가 코드에서 stream으로 사용하는 것이, Stream API입니다.

// 컬렉션에서 스트림 생성

Stream<Integer> stream = list.stream();

 

Stream API란, 컬렉션 또는 배열 인스턴스에 저장된 데이터를 가지고, 중간연산과 최종연산을 진행하기 좋은 구조로 배치시키는 복사본이라고 할 수 있습니다.

 

Stream API 특징

  1. 스트림은 외부 반복을 통해 작업하는 컬렉션과 다르게, 내부 반복을 통해 작업을 수행합니다.
  2. 스트림은 재사용이 가능한 컬렉션과 다르게 단 1번만 사용할 수 있습니다.
  3. 스트림은 원본 데이터를 변경하지 않고, 복사해서 사용됩니다.
  4. 스트림 연산은, 필터-맵(filter-map) 기반의 API를 사용하여 지연(Lazy) 연산을 통해 성능을 최적합니다.
  5. 스트림은 parallelStream() 메소드를 통한 병렬처리를 지원합니다.

 

 

Stream API 사용 예시


1. Stream API 생성 (feat stream.of)

 

(1) List to Stream

-> Collection 인터페이스에 정의되어있는, Stream() 메소드를 사용합니다.

-> 배열 등, 여러 데이터를 가지는 집합들에 의해 사용가능합니다.

public class prog {
	public static void main(String[] args){
		ArrayList<Integer> list = new ArrayList<Integer>();
		
		list.add(4);
		list.add(2);
		list.add(3);
		list.add(1);
		
		// 컬렉션에서 스트림 생성
		Stream<Integer> stream = list.stream();
		// forEach() 메소드를 이용한 스트림 요소의 순차 접근
		stream.forEach(System.out::println);		
	}
}

 

 

(2) Steam.of()

-> Stream.of() 메소드를 이용해 Stream 객체를 바로 생성할 수 있습니다.

// 가변 매개변수에서 스트림 생성

Stream<Double> stream = Stream.of(4.2, 2.5, 3.1, 1.9);

stream.forEach(System.out::println);

 


2. Stream API  중개 연산 (Stream to Stream)

  • 스트림을 전달받아, 연산 후  다시 스트림으로 반환하는 연산입니다.
  • 스트림의 중개 연산은 필터-맵(filter-map) 기반의 API를 사용함으로 지연(lazy) 연산을 통해 성능을 최적화할 수 있습니다.

 

 

스트림 API에서 사용할 수 있는 대표적인 중개 연산과 그에 따른 메소드는 다음과 같습니다.

  1. 스트림 필터링 : filter(), distinct()
  2. 스트림 변환 : map(), flatMap()
  3. 스트림 제한 : limit(), skip()
  4. 스트림 정렬 : sorted()
  5. 스트림 연산 결과 확인 : peek()

 

[Stream 중개 연산 예시]

final List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
 
System.out.println(
    list.stream()
        .filter(i -> i<6)
        .filter(i -> i%2==0)
        .map(i -> i*10)
        .collect(Collectors.toList())
);


//결과
[20, 40]


출처: https://dororongju.tistory.com/137 [웹 개발 메모장]

 

[Stream 중개 연산 메소드]

메소드 설명
Stream<T> filter(Predicate<? super T> predicate) 해당 스트림에서 주어진 조건(predicate)에 맞는 요소만으로 구성된 새로운 스트림을 반환함.
<R> Stream<R> map(Functoin<? super T, ? extends R> mapper) 해당 스트림의 요소들을 주어진 함수에 인수로 전달하여, 그 반환값으로 이루어진 새로운 스트림을 반환함.
<R> Stream<R> flatMap(Functoin<? super T, ? extends Stream<? extends R>> mapper) 해당 스트림의 요소가 배열일 경우, 배열의 각 요소를 주어진 함수에 인수로 전달하여, 그 반환값으로 이루어진 새로운 스트림을 반환함.
Stream<T> distinct() 해당 스트림에서 중복된 요소가 제거된 새로운 스트림을 반환함.
내부적으로 Object 클래스의 equals() 메소드를 사용함.
Stream<T> limit(long maxSize) 해당 스트림에서 전달된 개수만큼의 요소만으로 이루어진 새로운 스트림을 반환함.
Stream<T> peek(Consumer<? super T> action) 결과 스트림으로부터 각 요소를 소모하여 추가로 명시된 동작(action)을 수행하여 새로운 스트림을 생성하여 반환함.
Stream<T> skip(long n) 해당 스트림의 첫 번째 요소부터 전달된 개수만큼의 요소를 제외한 나머지 요소만으로 이루어진 새로운 스트림을 반환함.
Stream<T> sorted()
Stream<T> sorted(Comparator<? super T> comparator)
해당 스트림을 주어진 비교자(comparator)를 이용하여 정렬함.
비교자를 전달하지 않으면 영문사전 순(natural order)으로 정렬함.

 


3. 스트림 최종연산

 

중개연산되어 반환된 스트림은, 마지막으로 최종연산을 수행하여 각 요소를 소모해 결과를 도출할 수 있습니다.

 

 

스트림 API에서 사용할 수 있는 대표적인 최종 연산과 그에 따른 메소드는 다음과 같습니다.

  1. 요소의 출력 : forEach()
  2. 요소의 소모 : reduce()
  3. 요소의 검색 : findFirst(), findAny()
  4. 요소의 검사 : anyMatch(), allMatch(), noneMatch()
  5. 요소의 통계 : count(), min(), max()
  6. 요소의 연산 : sum(), average()
  7. 요소의 수집 : collect()

 

 

[사용 예시]

1. Stream forEach

Stream<String> stream = Stream.of("넷", "둘", "셋", "하나");

stream.forEach(System.out::println);

/*실행 결과
넷
둘
셋
하나
*/

 


2. stream anymatch() / stream allmatch()

해당 스트림의 요소 중에서 특정 조건을 만족하는 요소가 있는지, 아니면 모두 만족하거나 모두 만족하지 않는지를 다음 메소드를 사용하여 확인할 수 있습니다.

 

  1. anyMatch() : 해당 스트림의 일부 요소가 특정 조건을 만족할 경우에 true를 반환함.
  2. allMatch() : 해당 스트림의 모든 요소가 특정 조건을 만족할 경우에 true를 반환함.

 

IntStream stream1 = IntStream.of(30, 90, 70, 10);

IntStream stream2 = IntStream.of(30, 90, 70, 10);

 

System.out.println(stream1.anyMatch(n -> n > 80));

System.out.println(stream2.allMatch(n -> n > 80));


/*실행 결과
true

false*/

 


3. 요소의 통계 : count(), min(), max() / 요소 연산 : sum(), average()

IntStream stream1 = IntStream.of(30, 90, 70, 10);

IntStream stream2 = IntStream.of(30, 90, 70, 10);

 

System.out.println(stream1.count());

System.out.println(stream2.max().getAsInt());

/*실행 결과
4
90*/

4. 요소 수집 (List, Collector 반환)

스트림 요소의 수집 용도별 사용할 수 있는 Collectors 메소드는 다음과 같습니다.

  1. 스트림을 배열이나 컬렉션으로 변환 : toArray(), toCollection(), toList(), toSet(), toMap()
  2. 요소의 통계와 연산 메소드와 같은 동작을 수행 : counting(), maxBy(), minBy(), summingInt(), averagingInt() 등
  3. 요소의 소모와 같은 동작을 수행 : reducing(), joining()
  4. 요소의 그룹화와 분할 : groupingBy(), partitioningBy()

 

Stream<String> stream = Stream.of("넷", "둘", "하나", "셋");

List<String> list = stream.collect(Collectors.toList());
Iterator<String> iter = list.iterator();

while(iter.hasNext()) {
    System.out.print(iter.next() + " ");
}


//넷 둘 하나 셋

 

대표적인 최종 연산 메소드

 

메소드 설명
void forEach(Consumer<? super T> action) 스트림의 각 요소에 대해 해당 요소를 소모하여 명시된 동작을 수행함.
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
처음 두 요소를 가지고 연산을 수행한 뒤, 그 결과와 다음 요소를 가지고 또다시 연산을 수행함. 이런 식으로 해당 스트림의 모든 요소를 소모하여 연산을 수행하고, 그 결과를 반환함.
Optional<T> findFirst()
Optional<T> findAny()
해당 스트림에서 첫 번째 요소를 참조하는 Optional 객체를 반환함.
(findAny() 메소드는 병렬 스트림일 때 사용함)
boolean anyMatch(Predicate<? super T> predicate) 해당 스트림의 일부 요소가 특정 조건을 만족할 경우에 true를 반환함.
boolean allMatch(Predicate<? super T> predicate) 해당 스트림의 모든 요소가 특정 조건을 만족할 경우에 true를 반환함.
boolean noneMatch(Predicate<? super T> predicate) 해당 스트림의 모든 요소가 특정 조건을 만족하지 않을 경우에 true를 반환함.
long count() 해당 스트림의 요소의 개수를 반환함.
Optional<T> max(Comparator<? super T> comparator) 해당 스트림의 요소 중에서 가장 큰 값을 가지는 요소를 참조하는 Optional 객체를 반환함.
Optional<T> min(Comparator<? super T> comparator) 해당 스트림의 요소 중에서 가장 작은 값을 가지는 요소를 참조하는 Optional 객체를 반환함.
T sum() 해당 스트림의 모든 요소에 대해 합을 구하여 반환함.
Optional<T> average() 해당 스트림의 모든 요소에 대해 평균값을 구하여 반환함.
<R,A> R collect(Collector<? super T,A,R> collector) 인수로 전달되는 Collectors 객체에 구현된 방법대로 스트림의 요소를 수집함.

 

 

 

 

 

Stream 은 자바 8부터 사용할 수 있다.

 

 

 


4. Stream 통계 연산

 

https://madplay.github.io/post/java-streams-terminal-operations

 

자바 스트림 정리: 3. 스트림 결과 구하기

원하는 형태로 가공한 스트림에서 결과를 구하는 연산의 종류에는 무엇이 있을까?

madplay.github.io

 

 

 

 


*참고

TCP School.- Stream API

https://codechacha.com/ko/stream-filter/