티스토리 뷰

5.1 필터링

5.1.1 프레디케이트로 필터링

  • 스트림 인터페이스는 filter 메서드를 지원함. filter 메서드는 프레디케이트를 인수로 받아서 프레디케이트와 일치하는 모든 요소를 포함하는 스트림을 반환함.
// 프레디케이트 필터링
List<Dish> vegetarianMenu = menu.stream()
	.filter(Dish::isVegetarian)
	.collect(Collectors.toList());

 

5.1.2 고유 요소 필터링

  • 스트림은 고유 요소로 이루어진 스트림을 반환하는 distinct 메서드도 지원함.
// 고유 요소 필터링
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);

 

5.2 스트림 슬라이싱

5.2.1 프레디케이트를 이용한 슬라이싱

  • 자바 9은 스트림의 요소를 효과적으로 선택할 수 있도록 takeWhile, dropWhile 두 가지 새로운 메서드를 지원함.
  • takeWhile을 이용하면 무한 스트림을 포함한 모든 스트림에 프레디케이트를 적용해 스트림을 슬라이스 할 수 있음.
  • dropWhile은 프레디케이트가 처음으로 거짓이 되는 지점까지 발견된 요소를 버림.
List<Dish> specialMenu = Arrays.asList(
	new Dish("seasonal fruit", true, 120, Type.OTHER),
	new Dish("prawns", false, 300, Type.FISH),
	new Dish("rice", true, 350, Type.OTHER),
	new Dish("chicken", false, 400, Type.MEAT),
	new Dish("french fries", true, 530, Type.OTHER)
);

// 320 초과한 값이 나오면 stop
List<Dish> slicedMenu1 = specialMenu.stream()
	.takeWhile(dish -> dish.getCalories() < 320)
	.collect(Collectors.toList());

// 320 이하는 다 버림
List<Dish> slicedMenu2 = specialMenu.stream()
	.dropWhile(dish -> dish.getCalories() < 320)
	.collect(Collectors.toList());

 

5.2.2 스트림 축소

  • 스트림은 주어진 값 이하의 크기를 갖는 새로운 스트림을 반환하는 limit(n) 메서드를 지원함.
List<Dish> dishes1 = specialMenu.stream()
	.filter(dish -> dish.getCalories() > 300)
	.limit(3)
	.collect(Collectors.toList());

 

5.2.3 요소 건너뛰기

  • 스트림은 처음 n개 요소를 제외한 스트림을 반환하는 skip(n) 메서드를 지원함.
List<Dish> dishes2 = specialMenu.stream()
	.filter(dish -> dish.getCalories() > 300)
	.skip(2)
	.collect(Collectors.toList());

 

5.3 매핑

5.3.1 스트림의 각 요소에 함수 적용하기

  • 스트림은 함수를 인수로 받는 map 메서드를 지원함.
  • 인수로 제공된 함수는 각 요소에 적용되며 함수를 적용한 결과가 새로운 요소로 매핑됨.
List<String> dishName = menu.stream()
	.map(Dish::getName)
	.collect(Collectors.toList());

 

5.3.2 스트림 평면화

  • flatMap 메서드는 스트림의 각 값을 다른 스트림으로 만든 다음 모든 스트림을 하나의 스트림으로 연결하는 기능을 수행.
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
List<int[]> pairs = numbers1.stream()
	.flatMap(i -> numbers2.stream().map(j -> new int[] {i, j}))
	.filter(ints -> (ints[0] + ints[1] % 3 == 0))
	.collect(Collectors.toList());

 

5.4 검색과 매칭

5.4.1 프레디케이트가 적어도 한 요소와 일치하는지 확인

  • 프레디케이트가 주어진 스트림에서 적어도 한 요소와 일치하는지 확인할 때 anyMatch 메서드를 이용함.
  • 하나라도 있으면 true를 반환함.
if (menu.stream().anyMatch(Dish::isVegetarian)) {
	System.out.println("The menu is (somewhat) vegetarian friendly!");
}

 

5.4.2 프레디케이트가 모든 요소와 일치하는지 검사

  • allMatch 메서드는 스트림의 모든 요소가 주어진 프레디케이트와 일치하는지 검사함.
boolean isHealthy1 = menu.stream().allMatch(dish -> dish.getCalories() < 1000);
  • noneMatch는 주어진 프레디케이트와 일치하는 요소가 없는지 확인함.
boolean isHealthy2 = menu.stream().noneMatch(dish -> dish.getCalories() >= 1000);
  • anyMatch, allMatch, noneMatch 세 메서드는 스트림 쇼트서킷 기법을 활용함.

 

5.4.3 요소 검색

  • findAny 메서드는 현재 스트림에서 임의의 요소를 반환함.
Optional<Dish> dish = menu.stream()
	.filter(Dish::isVegetarian)
	.findAny();

 

5.4.4 첫 번째 요소 찾기

  • findFirst()는 스트림에서 첫 번째 요소를 반환하는 메서드.
List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> firstSquareDivisibleByThree = someNumbers.stream()
	.map(n -> n * n)
	.filter(n -> n % 3 == 0)
	.findFirst();

 

5.5 리듀싱

  • 모든 스트림 요소를 처리해서 값으로 도출하는 연산을 리듀싱 연산이라고 함.

 

5.5.1 요소의 합

int sum = 0;
for (int x : numbers) {
	sum += x;
}
  • 위 코드를 reduce 메서드를 이용해서 아래와 같이 표현할 수 있음.
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
  • 초기값 0, 두 요소를 조합해서 새로운 값을 만드는 BinaryOperator<T>.
Optional<Integer> sumOptional = numbers3.stream().reduce(Integer::sum);
  • 초기값이 없어도 되는데, 없는 경우는 Optional을 반환함. 스트림에 아무 요소도 없는 경우 합계를 반환할 수 없기 때문에 Optional로 반환함.

 

5.5.2 최대값과 최소값

  • 최대값과 최소값을 찾을 때도 reduce를 활용할 수 있음.
Optional<Integer> max = numbers3.stream().reduce(Integer::max);
Optional<Integer> min = numbers3.stream().reduce(Integer::min);

 

5.6 실전 연습

 

5.7 숫자형 스트림

5.7.1 기본형 특화 스트림

  • 자바 8에서는 세 가지 기본형 특화 스트림을 제공함
  • 스트림 API는 박싱 비용을 피할 수 있도록 'int 요소에 특화된 IntStream', 'double 요소에 특화된 DoubleStream', 'long 요소에 특화된 LongStream'을 제공함.
  • 각각의 인터페이스는 숫자 스트림의 합계를 계산하는 sum, 최댓값 요소를 검색하는 max 같이 자주 사용하는 숫자 관련 리듀싱 연산 수행 메서드를 제공함. 또한 필요할 때 다시 객체 스트림으로 복원하는 기능도 제공함.
int calories = menu.stream()
	.mapToInt(Dish::getCalories)
    	.sum();
  • 스트림을 특화 스트림으로 변환할 때는 mapToInt, mapToDouble, mapToLong 세 가지 메서드를 가장 많이 사용함.
  • 이들 메서드는 Stream<T> 대신 특화된 스트림을 반환함.
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream = intStream.boxed();
  • boxed 메서드를 이용하면 특화 스트림에서 일반 스트림으로 변환할 수 있음.
  • Optional 또한 OptionalInt, OptionalDouble, OptionalLong 세 가지 기본형 특화 스트림 버전도 제공함.

5.7.2 숫자 범위

  • 자바 8의 IntStream과 LongStream에서는 range와 rangeClosed 두 가지 정적 메서드를 제공함.
  • 두 메서드는 모두 첫 번째 인수로 시작값을, 두 번째 인수로 종료값을 가짐.
  • range 메서드는 시작값과 종료값이 결과에 포함되지 않는 반면 rangeClosed는 시작값과 종료값이 결과에 포함됨.
IntStream evenNumbers = IntStream.rangeClosed(1, 100)
	.filter(n -> n % 2 == 0);

 

5.8 스트림 만들기

5.8.1 값으로 스트림 만들기

  • 임의의 수를 인수로 받는 정적 메서드 Stream.of를 이용해서 스트림을 만들 수 있음.
Stream<String> stream = Stream.of("Modern ", "Java ", "In ", "Action");

 

5.8.2 null이 될 수 있는 객체로 스트림 만들기

Stream<String> homeValueStream = Stream.ofNullable(System.getProperty("home"));

 

 

5.8.3 배열로 스트림 만들기

  • 배열을 인수로 받는 정적 메서드 Arrays.stream을 이용해서 스트림을 만들 수 있음.
int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum();

 

5.8.4 파일로 스트림 만들기

  • Files.lines로 파일의 각 행 요소를 반환하는 스트림을 얻을 수 있음.

 

5.8.5 함수로 무한 스트림 만들기

  • 스트림 API는 함수에서 스트림을 만들 수 있는 두 정적 메서드 Stream.iterate와 Stream.generate를 제공함.
  • 두 연산을 이용해서 무한 스트림, 크기가 고정되지 않은 스트림을 만들 수 있음.
  • iterate 메서드는 초기값과 람다를 인수로 받아서 새로운 값을 끊임없이 생산할 수 있음.
  • generate 메서드도 무한 스트림을 만들 수 있음. 그러나 generate는 생산된 값을 연속적으로 계산하는 것이 아니라, Supplier<T>를 인수로 받아서 새로운 값을 생성해냄.

 

5.9 마치며

  • 스트림 API를 이용하면 복잡한 데이터 처리 질의를 표현할 수 있음.
  • filter, distinct, takeWhile, dropWhile, skip, limit 메서드로 스트림을 필터링하거나 자를 수 있음.
  • 소스가 정렬되어 있다는 사실을 알고 있을 때 takeWhile과 dropWhile 메소드를 효과적으로 사용할 수 있음.
  • map, flatMap 메서드로 스트림의 요소를 추출하거나 변환할 수 있음.
  • findFirst, findAny 메서드로 스트림의 요소를 검색할 수 있음. allMatch, noneMatch, anyMatch 메서드를 이용해서 주어진 프레디케이트와 일치하는 요소를 스트림에서 검색할 수 있음.
  • 이들 메서드는 쇼트서킷 (short-circuit), 즉 결괄르 찾는 즉시 반환하며, 전체 스트림을 처리하지는 않음.
  • reduce 메서드로 스트림의 모든 요소를 반복 조합하며 값을 도출할 수 있음. 예를 들어 reduce로 스트림의 최댓값이나 모든 요소의 합계를 계산할 수 있음.
  • filter, map 등은 상태를 저장하지 않는 상태 없는 연산임. reduce 같은 연산은 값을 계산하는 데 필요한 상태를 저장함. sorted, distinct 등의 메서드는 새로운 스트림을 반환하기에 앞서 스트림의 모든 요소를 버퍼에 저장해야 함. 이런 메서드를 상태 있는 연산이라고 부름.
  • IntStream, DoubleStream, LongStream은 기본형 특화 스트림임. 이들 연산은 각각의 기본형에 맞게 특화되어 있음.
  • 컬렉션 뿐 아니라 값, 배열, 파일, iterate와 generate 같은 메서드로도 스트림을 만들 수 있음.
  • 무한한 개수의 요소를 가진 스트림을 무한 스트림이라 함.
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함