코린이의 소소한 공부노트

스트림의 중간 연산 본문

Java

스트림의 중간 연산

무지맘 2023. 2. 7. 10:57

[중간 연산이란?]

1. 연산 결과가 스트림인 연산

2. 반복적으로 적용이 가능하다.

 

[중간 연산 종류]

1. 스트림 자르기: skip(), llimit()

// 앞에서부터 n개 건너뛰기
Stream<T> skip(long n)

// maxSize 이후의 요소는 잘라냄
Stream<T> limit(long maxSize)

// 예시
IntStream intStream = IntStream.rangeClosed(1, 10); // 12345678910
intStream.skip(3).limit(5).forEach(System.out::print); // 45678 (3개 건너뛰고, 5개 자름)

2. 스트림의 요소 걸러내기: filter(), distinct()

// 조건에 맞지 않는 요소 제거
Stream<T> filter(Predicate<? super T> predicate)

// 중복제거
Stream<T> distinct()

// 예시
IntStream intStream = IntStream.of(1,2,2,3,3,3,4,5,5,6);
intStream.distinct().forEach(System.out::print); // 123456 (중복 제거후 출력)

IntStream intStream = IntStream.rangeClosed(1, 10); // 12345678910
intStream.filter(i->i%2==0).forEach(System.out::print); // 246810 (조건에 맞는 것만 통과)
intStream.filter(i->i%2!=0 && i%3!=0).forEach(System.out::print); // 157
intStream.filter(i->i%2!=0).filter(i->i%3!=0).forEach(System.out::print); // 위의 코드와 같음

3. 스트림 정렬하기: sorted()

// 스트림 요소의 기본 정렬(Comparable)로 정렬
Stream<T> sorted()

//지정된 Comparator로 정렬
Stream<T> sorted(Comparator<? super T> comparator)

// 예시
Stream<String> strStream = Stream.of(“dd”, “aaa”, “CC”, “cc”, “b”);

// 기본 정렬 (1) 스트림 요소의 Comparable로 정렬. 대문자가 먼저 나옴
strStream.sorted(); // “CCaaabccdd”
// 기본 정렬 (2) 지정된 Comparator로 정렬
strStream.sorted(Comparator.naturalOrder()); // “CCaaabccdd”
// 람다식도 가능
strStream.sorted(s1, s2 -> s1.compareTo(s2)); // “CCaaabccdd”
// 위의 문장과 동일(메서드 참조)
strStream.sorted(String::compareTo); // “CCaaabccdd”

// 역순 정렬
strStream.sorted(Comparator.reverseOrder()); // “ddccbaaaCC”
strStream.sorted(Comparator.<String>naturalOrder().reversed()); // “ddccbaaaCC”

// String 클래스의 static 멤버
static Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
// 대소문자 구분 안하는 기본 정렬. 대문자가 먼저 나옴
strStream.sorted(String.CASE_INSENSITIVE_ORDER); // “aaabCCccdd”

// 대소문자 구분 안하는 역순 정렬. 여기서도 대문자가 먼저 나옴
strStream.sorted(String.CASE_INSENSITIVE_ORDER.reversed()); // “ddCCccbaaa”

// 길이 순 정렬
strStream.sorted(Comparator.comparing(String::length)); // “bddCCccaaa”
// no 오토박싱
strStream.sorted(Comparator.comparingInt(String::length)); // “bddCCccaaa”

// 길이 역순 정렬. 여기서도 대문자가 먼저 나옴
strStream.sorted(Comparator.comparing(String::length).reveresed()); // “aaaddCCccb”

// Comparator의 comparing()으로 정렬 기준을 제공
comparing(Function<T,U> keyExtractor)
comparing(Function<T,U> keyExtractor, Comparator<U> keyComparator)
// 추가 정렬 기준을 제공
thenComparing(Comparator<T> other)
thenComparing(Function<T,U> keyExtractor)
thenComparing(Function<T,U> keyExtractor, Comparator<U> keyComp)

// 중간 연산이기 때문에 여러번 가능
studentStream.sorted(Comparator.comparing(Student::getBan)  // 반별로 정렬
                    .thenComparing(Student::getTotalScore)  // 총점별로 정렬
                    .thenComparing(Student::getName)  // 이름별로 정렬
                    .forEach(Sysetm.out::println));

4. 스트림의 요소 변환하기: map()

// 스트림의 요소를 함수를 이용해 변환. 중간 연산의 핵심
Stream<R> map(Function<T,R> mapper)
IntStream mapToInt(ToIntFunction<T> mapper)
LongStream mapToLong(ToLongFunction<T> mapper)
DoubleStream mapToDouble(ToDoubleFunction<T> mapper)

// 예시1. map()을 이용해 Stream<File>을 Stream<String>으로 변환
Stream<File> fileStream = Stream.of(new File("Ex1.java"), new File("Ex1"),
          new File("Ex1.bak"), new File("Ex2.java"), new File("Ex1.txt"));
Stream<String> filenameStream = fileStream.map(File::getName); // 람다식: File f -> f.getName()
filenameStream.forEach(System.out::println); // 스트림의 모든 파일의 이름을 출력

// 예시2. 파일 스트림(Strem<File>)에서 파일 확장자(대문자)를 중복없이 뽑아내기
fileStream.map(File::getName) // Stream<File>을 파일 이름이 담긴 Stream<String>으로
   .filter(s->s.indexOf('.')!=-1) // 확장자가 없는 것은 제외
   .map(s->s.substring(s.indexOf('.')+1)) // Stream<String>에서 확장자만 뽑아 Stream<String>으로
   .map(String::toUpperCase) // 확장자를 대문자 Stream<String>으로
   .distinct() // 중복 제거
   .forEach(System.out::print); // JAVABAKTXT

5. 스트림의 요소를 소비하지 않고 엿보기: peek()

// 스트림을 소비하지 않고 스트림 요소에 작업을 수행
Stream<T> peek(Consumer<? super T> action)

// 예시
Stream<File> fileStream = Stream.of(new File("Ex1.java"), new File("Ex1"),
          new File("Ex1.bak"), new File("Ex2.java"), new File("Ex1.txt"));
          
fileStream.map(File::getName) // Stream<File> → Stream<String>
    .filter(s -> s.indexOf('.')!=-1) // 확장자가 없는 것은 제외
    .peek(s->System.out.printf("filename=%s ", s)) // 파일명을 출력해서 중간 확인
    .map(s -> s.substring(s.indexOf('.')+1)) // 확장자만 추출
    .peek(s->System.out.printf("extension=%s ", s)) // 확장자를 출력해서 중간 확인
    .forEach(System.out::println); // 출력. 최종연산 스트림을 소비
// 결과
filename=Ex1.java extension=java JAVA
filename=Ex1.bak extension=bak BAK
filename=Ex1.txt extension=txt TXT

6. 스트림의 스트림을 스트림으로 변환: flatMap()

// 스트림의 요소를 함수를 이용해 변환. 중간 연산의 핵심2
Stream<R> flatMap(Function<T,Stream<R>> mapper)
IntStream flatMapToInt(Function<T,IntStream> mapper)
LongStream flatMapToLong(Function<T,LongStream> mapper)
DoubleStream flatMapToDouble(Function<T,DoubleStream> mapper)

// 예시
Stream<String[]> strArrStrm = Stream.of(new String[] {"abc", "def", "ghi" },
                                        new String[] {"ABC", "GHI", "JKLMN"});

Stream<Stream<String>> strStrStrm = strArrStrm.map(Arrays::stream);
// map()을 이용할 경우 스트림의 요소가 스트림이 된다.
// 스트림의 요소는 문자열 스트림, 총 2개
// 한 요소는 "abc", "def", "ghi"를 담은 스트림
// 다른 요소는 "ABC", "GHI", "JKLMN"을 담은 스트림

Stream<String> strStrStrm = strArrStrm.flatMap(Arrays::stream); // Arrays.stream(T[])
// flatmap()을 이용할 경우 스트림의 요소들을 다 합쳐 하나의 스트림에 담는다.
// 스트림의 요소는 문자열, 총 6개
// 요소는 "abc", "def", "ghi", "ABC", "GHI", "JKLMN"

 

'Java' 카테고리의 다른 글

스트림의 최종 연산  (0) 2023.02.21
Optional 클래스  (0) 2023.02.07
스트림 생성하기  (0) 2023.02.01
스트림의 정의와 특징  (0) 2023.01.30
람다식과 메서드 참조  (0) 2023.01.13