티스토리 뷰

728x90

필터링

Predicate로 필터링

스트림 인터페이스 중 filter 메서드는 Predicate(불리언을 반환하는 함수)를 인수로 받아서 Predicate와 일치하는 모든 요소를 포함하는 스트림을 반환한다.

List<Dish> vegetarianMenu = menu.stream()
                .filter(Dish::isVegetarian) //채식 요리인지 확인하는 메서드 참조
            	.collect(toList());

고유 요소 필터링

스트림은 고유 요소로 이루어진 스트림을 반환하는 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);

스트림 축소

스트림은 주어진 값 이하의 크기를 갖는 새로운 스트림을 반환하는 limit(n) 메서드를 지원한다.

스트림이 정렬되어 있으면 최대 요소 n개를 반환할 수 있다.

List<Dish> dishes = specialMenu.stream()
        .filter(d -> d.getCalories() > 300)
        .limit(3)
        .collect(toList());

만약 정렬되어 있지 않으면 limit의 결과도 정렬되지 않은 상태로 반환된다.

요소 건너뛰기

스트림은 처음 n개 요소를 제외한 스트림을 반환하는 skip(n) 메서드를 지원한다.

만약 n개 이하의 스트림의 요소에서 skip(n)을 호출하면 빈 스트림이 반환된다.

List<Dish> dishes = menu.stream()
        .filter(d -> d.getCalories() > 300)
        .skip(2)
        .collect(toList());

매핑

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

스트림은 함수를 인수로 받는 map 메서드를 지원한다. 인수로 제공된 함수는 각 요소에 적용되며 함수를 적용한 결과가 새로운 요소로 매핑된다.

List<String> dishNames = menu.stream()
        .map(Dish::getName)
        .collect(toList());
System.out.println(dishNames);

단어리스트가 주어졌을 때 각 단어가 포함하는 글자 수의 리스트를 반환한다고 하면?

List<String> words = Arrays.asList("Hello", "World");
List<Integer> wordLengths = words.stream()
        .map(String::length)
        .collect(toList());
System.out.println(wordLengths);

스트림 평면화

리스트에서 고유 문자로 이루어진 리스트를 반환해보자

[”Hello”, “World”] → 기대값은 [”H”, “e”, “l”, “o”, “W”, “r”, ”d”]

words.stream()
                .map(word -> word.split(""))
        .distinct()
        .forEach(System.out::println);

위 코드에서 map으로 전달한 람다는 Stream<String[]> 이 된다.

스트림을 평면화 하기 위해서 flatMap 사용

words.stream()
        .map(word -> word.split("")) //각 단어를 개별 문자를 포함하는 배열로 변환
        .flatMap(Arrays::stream) //생성된 스트림을 하나의 스트림으로 평면화
        .distinct()
        .forEach(System.out::println);

flatMap 메서드는 스트림의 각 값을 다른 스트림으로 만든 다음에 모든 스트림을 하나의 스트림으로 연결하는 기능을 수행한다.

검색과 매칭

anyMatch - 스트림에서 적어도 한 요소와 일치하는지 확인할 때 사용

//menu에 채식요리가 있는지 확인
menu.stream().anyMatch(Dish::isVegetarian)

allMatch - 스트림의 모든 요소가 주어진 프레디케이트와 일치하는지 검사

//모든 요리가 1000칼로리 밑인지 검사
menu.stream().allMatch(dish -> dish.getCalories() < 1000);

nonMatch - allMatch의 반대

위의 세 메서드는 스트림 쇼트서킷 기법 연산을 활용한다.

요소 검색

findAny - 스트림에서 임의의 요소를 반환

Optional<Dish> dish = menu.stream().filter(Dish::isVegetarian).findAny();

요소가 없을 수도 있기 때문에 Optional로 반환된다.

첫 번째 요소 찾기

findFirst - 스트림 요소에서 첫 번째 요소를 반환

//숫자 3으로 나누어 떨어지는 첫 번째 제곱값을 반환.
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();

숫자형 스트림

Stream은 숫자 스트림을 효율적으로 처리할 수 있도록 기본형 특화 스트림을 제공한다.

기본형 특화 스트림

스트림 API는 박싱 비용을 피할 수 있도록 3가지 기본형 특화 스트림을 제공한다.

IntStream, DoubleStream, LongStream

특화 스트림은 오직 박싱 과정에서 일어나는 효율성과 관련있으며 스트림에 추가 기능을 제공하지는 않는다.

int calories = menu.stream() //Stream<Dish> 반환
        .mapToInt(Dish::getCalories) //IntStream 반환
        .sum();
System.out.println("Number of calories:" + calories);

mapToInt 메서드가 IntStream을 반환하므로 IntStream 인터페이스에서 제공하는 sum 메서드를 사용할 수 있다. 만약 스트림이 비어있으면 sum은 기본값 0을 반환한다.

객체 스트림으로 복원하기

boxed 메서드를 이용해서 특화 스트림을 일반 스트림으로 변환할 수 있다.

IntStream intStream = menu.stream().mapToInt(Dish::getCalories); //숫자 스트림 변환
Stream<Integer> stream = intStream.boxed(); //숫자 스트림을 스트림으로 변환

Optional 도 OptionalInt, OptionalDouble, OptionalLong 세 가지 기본형 특화 스트림 버전도 제공한다.

숫자 범위

특정 범위의 숫자를 이용할 때는 IntStream과 LongStream에서 range와 rangeClosed 정적 메서드를 사용할 수 있다.

range 메서드는 시작값과 종료값이 결과에 포함되지 않는 반면 rangeClosed는 시작값과 종료값이 결과에 포함된다.

IntStream evenNumbers = IntStream.rangeClosed(1, 100); //시작값 종료값 포함
System.out.println(evenNumbers.count()); //50

스트림 만들기

값으로 스트림 만들기

임의의 수를 인수로 받는 정적 메서드 Stream.of을 이용해서 스트림을 만들 수 있다.

Stream<String> stream = Stream.of("Modern", "Java", "In", "Action");
stream.map(String::toUpperCase).forEach(System.out::println);

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

자바 9에서는 null이 될 수 있는 개체를 스트림으로 만들 수 있는 새로운 메서드가 추가

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

Stream<String> values = Stream.of("config", "home", "user")
                              .flatMap(key -> Stream.ofNullable(System.getProperty(key));

배열로 스트림 만들기

배열을 인수로 받는 정적 메서드 Arrays.stream을 이용해서 스트림을 만들 수 있다.

int[] numbers = {2,3,5,7,11,13};
int sum = Arrays.stream(numbers).sum();

파일로 스트림 만들기

자바의 NIO API도 스트림 API를 활용할 수 있도록 업데이트 되었다.

long uniqueWords = 0;
try(Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset()) {
    uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
                                         .distinct()
                               .count();
} catch(IOException e) {}

Stream 인터페이스는 AutoCloseable 인터페이스를 구현한다.

728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/12   »
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 31
글 보관함