7.1 스트림 슬라이싱
1. takeWhile의 활용
takeWhile 메서드는 Stream의 각 요소 중 조건을 만족하지 않는 첫 번째 요소를 만나면 현재까지의 요소를 반환합니다.
정렬된 경우
import java.util.List;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> result = numbers.stream()
.takeWhile(n -> n < 6)
.toList();
System.out.println(result); // [1, 2, 3, 4, 5]
}
}
정렬되지 않은 경우
import java.util.List;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3, 1, 7, 5, 2, 6, 4, 8);
List<Integer> result = numbers.stream()
.takeWhile(n -> n < 6)
.toList();
System.out.println(result); // [3, 1, 5, 2]
}
}
2. dropWhile의 활용
dropWhile 메서드는 처음으로 거짓이 되는 지점까지 발견된 요소들을 버리는 역할로 takeWhile의 정반대의 기능입니다.
import java.util.List;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 조건을 만족하지 않는 요소들을 제외한 후 나머지 요소들을 포함하는 스트림 생성
List<Integer> result = numbers.stream()
.dropWhile(n -> n < 6) // 6 이상인 요소들을 제외한 나머지 요소들을 포함하는 스트림 생성
.toList();
System.out.println(result); // [6, 7, 8, 9, 10]
}
}
3. skip과 limit의 활용
skip 메서드는 스트림에서 처음 몇 개의 요소를 건너뛴 다음에 나오는 요소들을 반환하고, limit 메서드는 처음 몇 개의 요소만을 반환하는 역할을 합니다.
import java.util.List;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 처음 2개의 요소를 건너뛰고 다음 3개의 요소만을 반환하는 스트림 생성
List<Integer> result = numbers.stream()
.skip(2) // 처음 2개의 요소를 건너뜀
.limit(3) // 다음 3개의 요소만을 반환
.toList();
System.out.println(result); // [3, 4, 5]
}
}
7.2 매핑
1. map의 활용
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
map은 스트림의 각 요소에 대해 특정 함수를 적용해 새로운 값으로 반환해 주는 역할을 합니다.
import java.util.List;
import java.util.Arrays;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 각 요소를 제곱하여 새로운 스트림 생성
List<Integer> squares = numbers.stream()
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println(squares); // [1, 4, 9, 16, 25]
}
}
2. flatMap의 활용
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
flatMap은 스트림의 각 요소에 대해 함수를 적용하고 학 함수가 반환한 스트림을 하나의 스트림으로 병합하는 기능을 제공합니다. 즉, 중첩된 구조를 펼쳐서 평면화된 요소를 하나의 스트림으로 합쳐 줍니다. (List<List<Integer>> -> List<Integer>)
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
class Person {
private String name;
private List<String> hobbies;
public Person(String name, List<String> hobbies) {
this.name = name;
this.hobbies = hobbies;
}
public List<String> getHobbies() {
return hobbies;
}
}
public class Main {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", Arrays.asList("Reading", "Traveling")),
new Person("Bob", Arrays.asList("Cooking", "Hiking"))
);
// 각 사람의 취미들을 평면화된 리스트로 변환
List<String> hobbies = people.stream()
.flatMap(person -> person.getHobbies().stream()) // 각 사람의 취미 리스트를 개별 스트림으로 변환하고 병합
.toList();
System.out.println(hobbies); // [Reading, Traveling, Cooking, Hiking]
}
}
7.3 무한 스트림 만들기
1. iterate 활용
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
// UnaryOperator
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
/**
* Returns a unary operator that always returns its input argument.
*
* @param <T> the type of the input and output of the operator
* @return a unary operator that always returns its input argument
*/
static <T> UnaryOperator<T> identity() {
return t -> t;
}
}
iterate 메서드는 seed라는 초기값을 받아서 UnaryOperator를 구현한 로직으로 seed값을 가공해 무한 스트림을 만들 수 있습니다.(Predicate로 조건 적용도 가능)
public static void main(String[] args) {
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 1)
.map(integer -> {
System.out.println(integer);
return integer;
})
.limit(10);
System.out.println("Hello");
infiniteStream.forEach(System.out::println);
}
// 실행 결과
// Hello
// 0
// 0
// 1
// 1
// 2
// 2
// ...
// 8
// 9
// 9
Stream의 연산은 lazy evaluation으로 인해서, Stream을 반환하는 중간 연산은 forEach, count, collect, average 등의 종료 연산을 만나기 전까지 호출이 지연된다는 특징이 있으며, 이를 위 코드의 실행 결과를 통해 확인할 수 있습니다.
2. generate의 활용
generate 메서드는 Supplier를 받아서 무한 스트림을 생성합니다. iterate 메서드와 동일하게 limit과 함께 조합하여 사용할 수 있습니다.
import java.util.Random;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// 난수 생성기를 이용하여 무한한 난수 스트림 생성
Stream<Integer> randomNumbers = Stream.generate(() -> new Random().nextInt(100));
// 처음 5개의 난수 출력 (무한 스트림이지만, limit를 사용하여 제한)
randomNumbers.limit(5)
.forEach(System.out::println);
}
}
'독서 > 모던 자바 인 액션' 카테고리의 다른 글
[자바] 스트림을 이용한 데이터 수집 - 그룹화 (1) | 2023.10.10 |
---|---|
[자바] 스트림을 이용한 데이터 수집 - Collectors (1) | 2023.10.05 |
데이터 컬렉션의 반복 처리 - 스트림(Stream) (1) | 2023.09.26 |
람다 표현식을 더 간결하게 - 메서드 참조 (0) | 2023.09.25 |
함수형 인터페이스를 통한 람다의 활용 (0) | 2023.09.24 |