Language/JAVA

#Stream

paran21 2022. 1. 19. 17:47

Stream의 특징

  • 원본의 데이터를 변경하지 않는다.
    • Stream<String> arrString = arr.stream();과 같이 별도의 복사본을 만든다.
  • 일회용이다 : 한번 사용이 끝난 후 Stream이 또 필요한 경우에는 Stream을 다시 생성해야 한다.
  • 내부 반복으로 작업을 처리하기 때문에 간결한 코드 작성이 가능하다.

함수형 인터페이스와 람다식

  • Stream은 매개변수로 함수형 인터페이스를 받음.
  • 람다식은 반환값으로 함수형 인터페이스를 반환 → Stream의 매개변수로 전달 가능
  • 람다식 : 함수형 인터페이스의 인스턴트를 생성하여 함수를 변수처럼 선언

 

Stream의 연산 종류

1. 생성하기

  • Stream객체를 생성하는 단계
  • Stream은 재사용이 불가능하므로, 닫히면 다시 생성해주어야 한다.
  • 배열, 컬렉션, 임의의 수, 파일 등 거의 모든 것을 가지고 스트림을 생성할 수 있다.

Collection 인터페이스 객체(List 등)

Stream<String> listStream = list.stream();

 

배열

Stream<String> stream = Stream.of("a", "b", "c");  //가변인자?? 나중에 찾아보기

Stream<String> stream = Stream.of(new String[]{"a", "b", "c"});

Stream<String> stream = Arrays.stream(new String[]{"a", "b", "c"});

 

원시Stream

IntStream stream = IntStream.range(4, 10); //4이상 10이하의 숫자를 갖는 IntStream;

LongSteram

DoubleStream

 

 

2. 가공하기

  • 원본의 데이터를 별도의 데이터로 가공하기 위한 중간 연산
  • 연산 결과를 Stream으로 다시 반환하기 때문에 연속해서 중간 연산을 이어갈 수 있다.

filter

  • 필터링
  • 함수 인자는 함수형 인터페이스 Predicate
  • .filter(name -> name.contains("a")); //a가 들어간 문자열만 포함하여 필터링

 

map

  • 변환
  • 함수 인자는 함수형 인터페이스 function
  • .map(s -> s.toUpperCase()); //모두 대문자로 변환
  • 메소드 참조를 이용해 변경 가능
  • .map(클래스명::메소드명)

 

sorted

  • 정렬
  • 오름차순 : .sorted()
  • 내림차순 : .sorted(Comparator.reverseOrder())

 

distinct

  • 중복 제거
  • Object의 equals()메소드를 이용
  • .distinct()
  • 생성한 클래스를 Stream으로 사용할 때는 equals와 hashCode를 오버라이드 해야함(https://mangkyu.tistory.com/114)

 

peek

  • Stream에 영향을 주지 않고 특정 연산 수행
  • 함수 인자는 함수형 인터페이스 Consumer
  • .peak(System.out::println) //stream의 요소들을 중간에 출력할 수 있다.

 

일반적인 Stream 객체 → 원시Stream

  • .mapToInt(), mapToLong(), mapToDouble()
  • .mapToInt(Double::intValue)

 

원시Stream → 일반적인 Stream 객체

  • .mapToObj(i -> "a" + i)

 

3. 결과 만들기

  • 가공된 데이터로부터 원하는 결과를 만들기 위한 최종 연산
  • Stream의 요소들을 소모하면서 연산이 수행되기 때문에 1번만 처리가능하다.

최종 연산들

  • 최대값 : .max()
  • 최소값 : .min()
  • 총합 : .sum()
  • 평균 : .average()
  • 개수 : .count()
  • min, max, average는 stream이 비어있는 경우 값을 특정할 수 없어 .ofElse(0)와 같이 optional로 값이 반환됨
  • sum과 count는 값이 비어있는 경우 0으로 값을 특정할 수 있어 원시 값 0을 반환

 

collect

  • Stream의 요소들을 List나 Set, Map 등 다른 종류의 결과로 사용하고 싶은 경우 사용
  • 함수 인자 : 인터페이스 Collector 타입
  • .collect(Collectors.toList()); //List로 반환
  • .collect(Collectors.toSet()); //Set으로 반환
  • .collect(Collectors.joining()) //String으로 이어붙이기
  •   - joining(구분자, 결과 맨 앞에 붙는 문자, 결과 맨 뒤에 붙는 문자)를 활용할 수 있다.
  • .collect(Collectors.avaeragingInt(클래스명::메소드명??)) //평균값
  • .collect(Collectors.summingInt(클래스명::메소드명??)) //총합
  • .collect(Collectors.summingInt(클래스명::메소드명??)) //IntSummaryStatics 객체가 반환됨(개수, 합계, 평균, 최소, 최대)
  • .collect(Collectors.groupingBy(클래스명::메소드명??))
  •   //그룹핑, 결과는 map으로 반환, 매개변수로 함수형 인터페이스Function이 필요함
  • .collect(Collectors.partitioningBy()) //함수형 인터페이스 Predicate를 받아 boolean 값을 key값으로 나눔

 

match

  • 조건 검사
  • 함수형 인터페이스 Predicate를 받아 검사, 결과는 boolean으로 반환
  • .anyMatch() //1개의 요소라도 해당 조건을 만족하는가
  • .allMatch() //모든 요소가 해당조건을 만족하는가
  • .noneMatch() //모든 요소가 해당조건을 만족하지 않은가

 

forEach

  • peek()와 유사하게 특정한 연산을 수행하지만, 최종 연산이기 때문에 실제 요소들에 영향을 줄 수 있다.
  • 반환값이 존재하지 않는다.
  • .forEach(System.out::println);

 

 

참고자료 : https://mangkyu.tistory.com/112

 

[Java] Stream API에 대한 이해 (1/5)

1. Stream API에 대한 이해 [ Stream API에 대한 소개 ] Java는 객체지향 언어이기 때문에 기본적으로 함수형 프로그래밍이 불가능하다. (함수형 프로그래밍에 대해 이해가 부족하다면 이 글을 참고하길

mangkyu.tistory.com