티스토리 뷰
개념
- 스트림의 요소를 선택하거나 스킵하는 다양한 방법에 대해 살펴보자.
Predicate
를 이용하는 방법, 스트림의 처음 몇 개의 요소를 무시하는 방법, 특정 크기로 스트림을 줄이는 방법 등 다양한 방법을 이용해 효율적으로 이런 작업을 수행할 수 있다.- 이러한 작업을 슬라이싱이라고 한다.
takeWhile 메서드
-
Java 9에 추가된 메서드
-
Predicate<T>
를 파라미터로 받아서 해당Predicate
가 false를 반환할 때까지의 요소를 취하는 메서드다. -
얼핏보면
filter
메서드와 유사해보이지만,filter
메서드가 전체 스트림에 대한Predicate
를 판단하는 반면takeWhile
은Predicate
가 false를 반환하는 순간 나머지 요소를 전부 버린다.- 아주 많은 요소를 가진 스트림에서는 이런 부분이 큰 차이를 유발할 수 있다.
- 특히, 정렬되어 있는 요소에 대해서 큰 장점을 가질 수 있다.
-
무한 스트림을 포함한 모든 스트림에
Predicate
를 적용해 스트림을 슬라이스할 수 있다.
dropWhile 메서드
- Java 9에 추가된 메서드
Predicate<T>
를 파라미터로 받아서 해당Predicate
가 false를 반환할 때까지의 요소를 모두 버리고 나머지 요소를 반환하는 메서드다.takeWhile
과 정반대로 작업을 수행한다.Predicate
가 false가 되는 지점에서 작업을 중단하고 남은 모든 요소를 반환한다.
limit 메서드
- 주어진 값 이하의 크기를 갖는 새로운 스트림을 반환하는 메서드
long
을 파라미터로 받아서 해당 숫자 이하의 요소를 반환- 소스가 정렬되어 있지 않았다면
limit
의 결과도 정렬되지 않은 상태로 반환된다.
skip 메서드
- 처음 n개 요소를 제외한 스트림을 반환하는 메서드
long
을 파라미터로 받아서 해당 숫자 이하의 요소를 버리고 나머지를 반환- n개 이하의 요소를 포함하는 스트림에
skip(n)
을 호출하면 빈 스트림이 반환된다.
예제
-
아래 예제에서 사용되는 내용들은 다양한 상황을 연출하기 위해서 임의로 만들어진 내용이므로 특정 속성에 대해서 왜 저 타입이 사용되었는지 의문을 가지지 말자!
-
예제 코드에서 사용되고 있는 스펙
- Java 15 preview (record라는 새로운 클래스 개념을 사용하기 위해서 해당 프리뷰 버전을 사용. 하위 버전의 경우는 일반 클래스를 생성한 후 getter를 만들고 사용하면 됨) - 참고
- JUnit 5
- Gradle 6.7
기본 데이터 생성
public record Song(int no, String title, String artist, int likeCount, LocalDate releasedDate) {
}
private final SlicingUsage slicingUsage = new SlicingUsage();
private final List<Song> songs = List.of(
new Song(1, "밤편지", "아이유", 393_424, LocalDate.of(2017, 3,24)),
new Song(2, "Love poem", "아이유", 280_586, LocalDate.of(2019, 11,1)),
new Song(3, "Blueming", "아이유", 280_323, LocalDate.of(2019, 11,18)),
new Song(4, "삐삐", "아이유", 264_664, LocalDate.of(2018, 10,10)),
new Song(5, "가을 아침", "아이유", 257_136, LocalDate.of(2017, 9,22)),
new Song(6, "팔레트", "아이유", 244_865, LocalDate.of(2017, 4,21)));
- 주어진 데이터가
likeCount
즉 좋아요 순으로 정렬되어 있다는 점에 집중하며 예제를 살펴보자.
특정 조건을 만족하는 노래들 조회
- 특정 조건을 만족하지 않는 데이터가 나타날 때까지의 요소를 반환하는 메서드를 만들어보자. (takeWhile 이용)
public List<Song> getSongsWithTakeWhile(List<Song> songs, Predicate<Song> predicate) {
return songs.stream()
.takeWhile(predicate)
.collect(Collectors.toList());
}
- 좋아요가 28만개 이상인 노래들을 조회해보자.
@Test
@DisplayName("좋아요가 28만개 이상인 노래들 조회")
void getSongsWithTakeWhileTest() {
final var result = slicingUsage.getSongsWithTakeWhile(songs, i -> i.likeCount() >= 280_000);
result.forEach(System.out::println);
assertEquals(3, result.size());
assertEquals("밤편지", result.get(0).title());
assertEquals("Love poem", result.get(1).title());
assertEquals("Blueming", result.get(2).title());
}
- 콘솔에 다음과 같은 실행 결과와 함께 테스트가 성공한다.
특정 조건을 만족하는 노래를 제외한 나머지 노래들 조회
- 특정 조건을 만족하지 않는 데이터가 나타날 때까지 요소를 버리고 나머지를 반환하는 메서드를 만들어보자. (dropWhile 이용)
public List<Song> getSongsWithDropWhile(List<Song> songs, Predicate<Song> predicate) {
return songs.stream()
.dropWhile(predicate)
.collect(Collectors.toList());
}
- 좋아요가 28만개보다 작은 요소들을 조회해보자.
@Test
@DisplayName("좋아요가 28만개 이상인 노래를 제외한 나머지 노래들 조회")
void getSongsWithDropWhileTest() {
final var result = slicingUsage.getSongsWithDropWhile(songs, i -> i.likeCount() >= 280_000);
result.forEach(System.out::println);
assertEquals(3, result.size());
assertEquals("삐삐", result.get(0).title());
assertEquals("가을 아침", result.get(1).title());
assertEquals("팔레트", result.get(2).title());
}
- 콘솔에 다음과 같은 실행 결과와 함께 테스트가 성공한다.
n개까지의 노래들 조회
- 스트림에서 n개의 요소를 반환하는 메서드를 만들어보자. (limit 이용)
public List<Song> getSongsWithLimit(List<Song> songs, int size) {
return songs.stream()
.limit(size)
.collect(Collectors.toList());
}
- 상위 2개의 노래들을 조회해보자.
@Test
@DisplayName("상위 2개 노래들 조회")
void getSongsWithLimitTest() {
final var result = slicingUsage.getSongsWithLimit(songs, 2);
result.forEach(System.out::println);
assertEquals(2, result.size());
assertEquals("밤편지", result.get(0).title());
assertEquals("Love poem", result.get(1).title());
}
- 콘솔에 다음과 같은 실행 결과와 함께 테스트가 성공한다.
n개를 제외한 나머지 노래들 조회
- 스트림에서 n개의 요소를 버리고 나머지를 반환하는 메서드를 만들어보자. (skip 이용)
public List<Song> getSongsWithSkip(List<Song> songs, int offset) {
return songs.stream()
.skip(offset)
.collect(Collectors.toList());
}
- 상위 4개를 노래를 건너띄고 나머지 노래들을 조회해보자.
@Test
@DisplayName("상위 4개를 제외한 나머지 노래들 조회")
void getSongsWithSkipTest() {
final var result = slicingUsage.getSongsWithSkip(songs, 4);
result.forEach(System.out::println);
assertEquals(2, result.size());
assertEquals("가을 아침", result.get(0).title());
assertEquals("팔레트", result.get(1).title());
}
- 콘솔에 다음과 같은 실행 결과와 함께 테스트가 성공한다.
이상 Stream API에서 사용하는 중간 연산 중 요소의 건너띄거나 특정 크기로 줄이는 등 슬라이싱 메서드들에 대해 살펴보았다.
'프로그래밍 > Java' 카테고리의 다른 글
[Stream API] 중간 연산 - flatMap 메서드 (0) | 2021.01.05 |
---|---|
[Stream API] 중간 연산 - map 메서드 (2) | 2021.01.04 |
[Stream API] 중간 연산 - distinct 메서드 (0) | 2020.12.31 |
[Stream API] 중간 연산 - filter 메서드 (2) | 2020.12.30 |
Intellij IDEA에서 Gradle을 사용해 Java Preview 버전의 코드 테스트하기. (0) | 2020.10.28 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- 계획
- flaMap
- 충북 콕! 콕!
- flatMapToDouble
- #React #ReactJS #리액트
- 람다
- Stream API
- 스트림
- flatMapToInt
- 변경사항
- 자바
- modern java
- 중간 연산
- lambda
- Java8
- 회고
- flatMapToLong
- #배열 #array #map 함수
- java
- 목표
- 익명 클래스
- import문
- #예제 #example #가계부 #Account Book
- java14
- 토이 프로젝트
- 다짐
- jdk14
- 개발자
- IntelliJ
- mapToObj
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함