[Java] Stream (스트림)

gyeol·2024년 3월 1일
0

자바

목록 보기
7/12
post-thumbnail

스트림

스트림은 자바 8 API에 새로 추가된 기능으로 스트림은 컬렉션의 저장요소를 하나씩 참조해 람다식으로 처리할 수 있도록 해주는 반복자이다.

특징

  • 람다식으로 요소 처리 코드 제공
  • 내부 반복자를 사용하기에 병렬 처리 쉬움
  • 중간 처리와 최종 처리를 할 수 있음

반복자 스트림

자바 7 이전까지는 List<String> 컬렉션에서 요소를 순차적으로 처리하기 위해 다음과 같이 사용했다.

List<String> LIST = Arrays.asList("홍길동", "신용권");
Iterator<String> iter = list.iterator();
while(iter.hasNext()){
	String name = iter.next();
    System.out.println(name);
}

이 코드를 Stream을 사용해 변경하면 다음과 같다.

List<String> list = Arrays.asList("홍길동", "신용권");
Stream<String> stream = list.stream();
stream.forEach(name -> ystem.out.println(name));

컬렉션의 stream() 메서드로 스트림 객체를 얻고 나서 stream.ForEach()를 사용해 컬렉션의 요소를 하나씩 출력한다.

스트림 파이프라인

대량의 데이터를 가공해 축소하는 것을 일반적으로 리덕션이라고 하느데 데이터의 합계, 평균값, 최대값 등이 대표적인 리덕션의 결과문이라고 볼 수 있다. 그러나 컬렉션의 요소를 리덕션의 결과물로 바로 집계할 수 없는 경우에는 집계하기 좋도록 필터링, 매핑, 정렬 등의 중간 처리가 필요하다.

double ageAvg = list.stream() //오리지널 스트림
	.filter(m->m.getSex() == Member.MALE) //중간 처리 스트림
    .mapToInt(Member::getAge) 
    .average() // 최종 처리
    .getAsDouble(); 

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

필터링은 중간 처리 기능을 요소를 걸러내는 역할을 한다.

  • distinct() : 중복 제거. Stream의 경우 Object.equals(Object)가 true이면 동일한 객체로 판단하고 중복을 제거한다.
  • filter() : 매개값으로 주어진 Predicate가 true를 리턴하는 요소만 필터링한다.
List<String> names = Arrays.asList("홍길동", "신용권", "신용권", "신민철");

names.stream().distinct().forEach(n->System.out.println(n));
//홍길동 신용권 신민철 출력
//중복값인 신용권 제거

names.stream().filter(n -> n.startsWith("신")).forEach(n -> System.out.println(n));
//신용권 신용권 신민철 출력
//첫 시작이 신인 이름만 출력됨

names.strea().filter(n -> n.startsWith("신")).forEach(n -> System.out.println(n));
//신용권 신민철
//신으로 시작되는 사람들 출력되지만 중복 값 제거

매핑(flatMapXXX(), mapXXX(), asXXXStream(), boxed())

매핑은 중간 처리 기능으로 스트림의 요소를 다른 요소로 대체하는 작업을 말한다.

  • flatMapXXX() : 요소를 대체하는 복수 개의 요소들로 구성된 새로운 스트림 리턴
List<String> inputList = Arrays.asList("10, 20, 30", "40, 50, 60");
inputList.flatMapToInt(data -> {
	String[] str = data.split(",");
    int[] intArr = new int[str.length];
    for(int i=0; i<str.length; i++){
    	intArr[i] = Integer.parseInt(str[i].trim());
    }
    return Arrays.stream(intArr);
 })
 .forEach(number -> System.out.println(number));
 
 /* 출력
 10
 20
 30
 40
 50
 60
 */
  • mapXXX() : 요소를 대체하는 요소로 구성된 새로운 스트림 리턴
List<Student> student = Arrays.asList(
	new Student("홍길동", 10),
    new Student("신용권", 20)
);

student.stream().mapToInt(Student :: getScore)
.forEach(score -> System.out.println(score));

/* 출력
10
20
*/
  • asXXXStream() : XXX 요소로 타입을 변환한다.
  • boxed() : int, long, double 요소를 Integer, Double, Long 요소로 박싱해서 Stream을 생성한다.
int[] arr = {1, 2, 3, 4, 5};

IntStream intStream = Arrays.stream(intArray);

intStream.asDoubleStream().forEach(d -> System.out.println(d));
// DoubleStream 생성

intStream = Arrays.stream(arr);
intStream.boxed().forEach(obj -> System.out.println(obj.intValue()));
//Stream<Integer> 생성

/** 출력
1.0
2.0
3.0
4.0
5.0

1
2
3
4
5
*/

사진출처 : https://velog.io/@mmy789/Java-%EC%8A%A4%ED%8A%B8%EB%A6%BC%EA%B3%BC-%EB%B3%91%EB%A0%AC-%EC%B2%98%EB%A6%AC-4

정렬 (sorted())

스트림은 요소가 최종 처리되기 전에 중간 단계에서 요소를 정렬해 최종 처리 순서를 변경할 수 있다.

루핑(peek(), forEach())

루핑은 요소 전체를 반복하는 것을 말한다. 루핑하는 메소드에는 peek(), forEach()가 있다.

  • peek() : 중간 처리 단계에서 전체 요소를 루핑하면서 추가적인 작업을 하기 위해 사용한다. 최정처리 메소드가 실행되지 않으면 지연되기 때문에 반드시 최종 처리 메소드가 호출되어야 한다.
intStream.filter(a -> a%2 == 0).peek(a -> System.out.println(a));
// 이렇게 적으면 스트림 동작하지 않음

intStream.filter(a -> a%2 == 0).peek(a -> System.out.println(a)).sum();
//요소 처리의 최종 단계가 합을 구하는 것이라면 peek 이후 sum 메서드 호출 필요
  • forEach() : 최종 처리 메소드이기 때문에 파이프라인 마지막에 루핑하면서 요소를 하나씩 처리한다.
int[] arr = {1, 2, 3, 4, 5};
Arrays.stream(arr).filter(a -> a%2==0).forEach(n -> System.out.println(n));
/** 출력
2
4
*/

매칭(allMatch(), anyMatch(), noneMatch())

스트림 클래스는 최종 처리 단계에서 요소들이 특정 조건에만족하는지 조사할 수 있는 메서드를 제공한다.

  • allMatch() : 모든 요소들이 매개값으로 주어진 Predicate의 조건을 만족하는지 검사한다.
  • anyMatch() : 최소한 한개의 요소가 매개값으로 주어진 Predicate의 조건을 만족하는지 검사한다.
  • noneMatch() : 모든 요소들이 매개값으로 주어진 Predicate의 조건을 만족하지 않는지 검사한다.

참고 : 이것이 자바다

profile
코딩 공부 기록중 '◡'

0개의 댓글