Stream API의 활용 및 사용법 -(4)

윤재열·2022년 11월 3일
0

Java

목록 보기
63/71
post-custom-banner

1. Stream 생성하기

  • Stream API를 사용하기 위해서는 먼저 Stream을 생성해주어야 합니다.
  • 타입에 따라 Stream을 생성하는 방법이 다른데, 여기서는 Collection과 Array에 대하여 Stream을 생성하는 방법에 대해 알아보도록 합니다.

Collection의 Stream 생성

  • Collection 인터페이스에는 stream()이 정의되어 있기 때문에 , Collection 인터페이스를 구현한 객체들(List,Set 등)은 모두 이 메서드를 이용해 Stream을 생성할 수 있습니다.
  • Stream()을 사용하면 해당 Collection의 객체를 소스로 하는 Stream으로 반환됩니다.
// List로부터 스트림을 생성
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> listStream = list.stream();

배열의 Stream 생성

  • 배열의 원소들을 소스로 하는 Stream을 생성하기 위해서는 Stream의 of 메서드 또는 Arrays의 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<String> stream = Arrays.stream(new String[] {"a", "b", "c"}, 0, 3); //end범위 포함 x

원시 Stream 생성

  • 위와 같이 객체를 위한 Stream 이외에도 int,long,double 같은 primitive 자료형들을 사용하기 위한 특수한 종류의 Stream 도 있습니다.
    • IntStream
    • LongStream
    • DoubleStream
  • IntStream 같은경우 range()함수를 사용하여 기존의 for 문을 대체할 수 있습니다.
// 4이상 9 이하의 숫자를 갖는 IntStream
IntStream stream = IntStream.range(4, 10);
// 결과 4,5,6,7,8,9
  • 추가로 range(),rangeClosed() 함수도 있는데
public static IntStream range(int startInclusive, int endExclusive) {
    ...
}

public static IntStream rangeClosed(int startInclusive, int endInclusive) {
    ...
}
  • 이처럼 인자값에도 힌트가 있듯이 range()는 종료값을 포함하지 않지만,rangeClosed()는 종료값을 포함해서 반환합니다.

2. Stream 가공하기(중간연산)

생성한 Stream 객체에서 요소들을 가공하기 위해서는 중간연산이 필요합니다. 가공하기 단계에 파라미터로는 앞서 설명하였던 함수형 인터페이스들이 사용되며. 여러개의 중간연산이 연결되도록 반환값으로 Stream으로 반환합니다.

필터링 [Filter]

  • Filter는 Stream에서 조건에 맞는 데이터만을 정제하여 더 작은 컬렉션을 만들어내는 연산입니다.
  • java 에서는 filter 함수의 인자로 함수형 인터페이스 Predicate를 받고 있기 때문에,boolean을 반환하는 람다식으로 작성하여 filter 함수를 구현할 수 있습니다.
  • 예를들어 어떤 String의 Stream에서 a가 들어있는 문자열만 포함하도록 필터링하는 예제를 보겠습니다.
Stream<String> stream = 
		list.stream()
		.filter(name -> name.contains("a"));

데이터 변환 [Map]

  • Map은 기존의 Stream 요소들을 변환하여 새로운 Stream을 형성하는 연산입니다.
  • 저장된 값을 특정한 형태로 변환하는데 주로 사용되며, Java에서는 map 함수의 인자로 함수형 인터페이스 function을 받고 있다. 예를 들어 String을 요소들로 갖는 Stream을 모두 대문자 String의 요소들로 변환하고자 할 때 map을 이용할 수 있다.
Stream<String> stream = 
  names.stream()
  .map(s -> s.toUpperCase());

정렬 [Sorted]

  • Stream의 요소들을 정렬하기 위해서는 sorted를 사용해야 하며, 파라미터로 Comparator를 넘길 수도 있습니다.
  • Comparator 인자 없이 호출할 경우 오름차순(ASC)로 정렬이 되며, 내림차순(DESC)로 정렬하기 위해서는 Comprator의 reverserOrder를 이용하면 됩니다.
  • 예를들어 어떤 Stream의 String 요소들을 정렬하기 위해서는 다음과 같이 sorted를 활용할 수 있습니다.
ist<String> list = Arrays.asList("Java", "Scala", "Groovy", "Python", "Go", "Swift");

Stream<String> stream = list.stream()
  .sorted()
// [Go, Groovy, Java, Python, Scala, Swift]

Stream<String> stream = list.stream()
  .sorted(Comparator.reverseOrder())
// [Swift, Scala, Python, Java, Groovy, Go]

중복제거[Distinct]

  • Stream의 요소들에 중복된 데이터가 존재하는 경우, 중복을 제거하기 위해 distinct를 사용할 수 있습니다.
  • distinct는 중복된 데이터를 검사하기 위해 Object의 equals()메서드를 사용합니다.
List<String> list = Arrays.asList("Java", "Scala", "Groovy", "Python", "Go", "Swift", "Java");

Stream<String> stream = list.stream()
  .distinct()
// [Java, Scala, Groovy, Python, Go, Swift]
  • 중요한점은 생성한 클래스를 Stream으로 사용한다고 하면,
    equals, hashCode를 오버라이드 해주어야 합니다!

특정 연산수행[Peek]

  • Stream의 요소들을 대상으로 Stream에 영향을 주지 않고 특정 연산을 수행하기 위한 peek 함수가 존재합니다.
  • '확인해본다' 라는 뜻을 지닌 peek 단어 처럼, peek 함수는 Stream의 각각의 요소들에 대해 특정 작업을 수행 할 뿐 결과에 영향을 주지 않습니다.
  • 또한 peek 함수는 파라미터로 함수형 인터페이스 Consumer를 인자로 받습니다.
  • 예를 들어 어떤 Stream의 요소들을 중간에 출력하기를 원할 때 다음과 같이 활용할 수 있습니다.
int sum = IntStream.of(1, 3, 5, 7, 9)
  .peek(System.out::println)
  .sum();

원시 Stream <-> Stream

  • 작업을 하다 보면 일반적인 Stream 객체를 원시 Stream으로 바꾸거나 그 반대로 하는 직업이 필요한 경우가 있습니다.
  • 이러한 경우를 위해서, 일반적인 Stream 객체는 mapToInt(),mapToLong(),mapToDouble() 이라는 특수한 Mapping 연산을 지원하고 있으며, 그 반대로 원시 객체는 mapToObject()를 통해 일반적인 Stream 객체로 바꿀 수 있습니다.
// IntStream -> Stream<Integer>
IntStream.range(1, 4)
    .mapToObj(i -> "a" + i)

// Stream<Double> -> IntStream -> Stream<String>
Stream.of(1.0, 2.0, 3.0)
    .mapToInt(Double::intValue)
    .mapToObj(i -> "a" + i)
profile
블로그 이전합니다! https://jyyoun1022.tistory.com/
post-custom-banner

0개의 댓글