5/2, 5/3, 5/7 스트림

박세현·2024년 5월 2일
0

JAVA

목록 보기
19/22
post-thumbnail

스트림(Stream)

  • 배열이든, 컬렉션이든 데이터 소스가 무엇이든 간에 Stream 객체로 변환하면 동일한 방식으로 처리 가능하게 함으로서 처리방식의 통일성을 주는 편의기능이다


예시)

ㄴ 배열이든 콜렉션이든 의도했던 기능은 다 똑같지만 형태(메서드, 클래스, 등등)가 다르다
-> 불편쓰
-> 그래서 스트림 등장

ㄴ 스트림객체가 된 이후 처리식이 배열이든 콜렉션이든 똑같음



1. 스트림이란?

  • java.util.stream

  • 배열이든, 컬렉션이든 데이터 소스가 무엇이든 간에 Stream 객체로 변환하면 동일한 방식으로 처리 가능 -> 처리방식의 통일성

  • 데이터 소스가 무엇이든 간에 같은 방식으로 다룰 수 있게 데이터를 추상화 하고 데이터를 다루는데 자주 사용되는 메서드들을 정의해 놓음

  • 데이터 군을 다룰때 많이 사용하는 기능을 모아 놓은 인터페이스(편의 기능)




2. 스트림의 특징

1) 스트림은 데이터 소스를 변경하지 않는다.

  • 원본 소스를 변경하지x
  • 내부적으로 복사해서 사용한다

예시)



2) 스트림은 일회용이다.

예시)

↓ 스트림은 일회용이기 때문에 새로 만들어야 가능


3) 스트림은 작업을 내부 반복으로 처리한다.

예시)


어디로 보내야 하낭,,,5/2 오후2시 강의...눈물난다...

ㄴ 함수형인터페이스가 매개변수로 쓰임...?
ㄴ map은 가리키는 역할...?
ㄴ 추상메서드 정의해줘야함




3. 스트림만들기

1) 컬렉션에서 생성하는 방법

	Collection
			Stream stream()
	Collection 인터페이스 - Stream<E> stream()
  • 스트림은 List, Set의 구현 객체만 생성 가능 -> Map은 안됨
  • 일반 스트림만 생성 가능 = 반환값이 일반스트림만 있음 : Stream<E>
  • 숫자 관련 편의 기능이 필요한 경우?
    • IntStream mapToInt(IntUnaryOperator..) : Stream<Integer> -> IntStream
    • LongStream mapToLong(LongUnaryOperator..) : Stream<Long> -> LongStream
    • DoubleStream mapToDouble(DoubleUnaryOperator ..) : Stream<Double> -> DoubleStream



2) 배열에서 생성하는 방법

	Arrays
		static stream(....)
	Arrays.stream(...)
  • 기본스트림, 일반스트림 둘다 생성 가능
  • 투입되는 자료형에 따라서 일반, 기본스트림 생성가능

  • 기본 자료형 스트림(기본 스트림)
    • int[] 배열 -> intStream
    • long[] 배열 -> LongStream
    • double[] 배열 -> DoubleStream
  • 일반 스트림
    • T[] 배열(참조 자료형 배열) -> Stream<T>

예시)

↓ 스트림객체가 됨

ㄴ 스트림 객체가 된 이후 배열이든 콜렉션이든 처리식이 똑같음



3) static of(T...)

	Stream
			.of(T... )

참고)
JDK8 부터 정적 메서드 of(...)가 주로 객체를 생성하는 역할을 한다.
-> of(...) : 객체 생성 메서드




4. 스트림 - 일반스트림, 기본자료형스트림

  • 일반 : Stream
  • 기본 : IntStream , LongStream , DoubleStream


1) Stream

Stream
  • 일반스트림


2) IntStream, LongStream, DoubleStream

IntStream 
LongStream 
DoubleStream 
  • 오토박싱, 언박싱이 발생 X -> 성능상 이점
  • 숫자(정수, 실수) 관련 편의 기능 제공(예 - 통계 관련 기능)
    -> 숫자에 특화된 편의기능
    ↔ 일반스트림은 숫자가 아닌 다른 자료형도 다루므로 숫자에 한정한 기능은 제공x

예시)



5. 스트림 변환(일반 스트림 ↔ 기본자료형스트림)

1) mapToInt, mapToLong, mapToDouble

  • 일반 스트림 -> 기본 자료형 스트림으로 변환 메서드
	mapToInt   : IntStream 
	mapToLong : LongStream
	mapToDouble : DoubleStream

참고)
map : 변경



예시1)

ㄴ 콜렉션(객체)으로는 연산이 안되니까 mapToInt를 통해 IntStream형태로 바꿔서 연산


예시2) 기본 자료형 스트림에서 일반 스트림(Stream<T>)에 있는 기능이 필요한 경우 있다.

sorted()IntStream(기본자료형스트림)에 정의된 기본정렬기능이다
ㄴ 기본정렬 : 오름차순
ㄴ 정렬을 바꾸고 싶네 ex) 내림차순...
ㄴ 근데 IntStream에는 정렬 기능 sorted() 메서드 1개만 정의되어있음
-> 대안기준x = 내림차순으로 변경불가


어 근데 일반 스트림 Stream<Integer>에는 sorted()sorted(Comparator...)가 정의되어 있다.
sorted(Comparator...) : 대안적인 기준 -> 내림차순정렬 가능
ㄴ 그러면 일반 스트림 Stream<Integer>을 통해서는 가능하지 않을까?
ㄴ 기본자료형스트림인 IntStream을 일반 스트림인 Stream<Integer>로 변환하고sorted(Comparator...) 통해서 정렬을 바꾸자ㅏㅏ


어떻게 바꾸지?
-> boxed() 통해서 바꿀 수 있음
IntStream .. boxed() -> Stream<Integer>



참고) 자바문서 IntStream
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/stream/IntStream.html

참고) 자바문서 Stream
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/stream/Stream.html



2) boxed

  • 기본 자료형 스트림 -> 일반 스트림 변환 메서드
	boxed())
    IntStream -> Stream<Integer>
    LongStream -> Stream<Long>


예시) 기본 자료형 스트림에서 일반 스트림(Stream<T>)에 있는 기능이 필요한 경우 있다.

ㄴ Comparator기능을 스기위해 일부러 기본자료형스트림에서 일반스트림으로 boxed()를 통해 변환함

ㄴ 일반스트림의 대안기준정렬 사용
ㄴ mapToInt를 통해 일반 스트림 -> 기본 자료형 스트림으로 다시 재 변환

ㄴ 내림차순으로 정렬됨





6. 스트림의 연산

1) 중간연산

  • 최종 연산이 호출되어야 수행되는 연산 : 지연된 연산
  • 연산이 최종 연산이 호출 될때가지는 연산x
  • 작업목록
  • 스트림 중간 부분에 정의된 메서드
  • 반환값이 Stream인 형태
    ㄴ 일반 스트림 - Stream<E>
    ㄴ 기본 자료형 스트림 - ntStream, LongStream, DoubleStream
  • 처리 할 작업을 나열하듯이 정의 : 메서드 체이닝



2) 최종연산

  • 스트림이 소비되면서 연산이 수행되고 작업이 완료
  • 가장 끝에 추가된 메서드
  • 반환값이 Stream이 아닌 형태
    ㄴ int, long, boolean, Optional...


3) 중간연산, 최종연산 구분하는 법

  • 자바문서를 보면서 반환값타입을 보고 구분
  • 중간연산 : 반환값이 Stream인 형태
  • 최종연산 : 반환값이 Stream이 아닌 형태

예시)

ㄴ predicate

ㄴ forEach가 최종연산기능
ㄴ forEach는 반환값이 void

ㄴ 최종연산이 나오기 전엔 연산이 실행되지 않음
ㄴ 스트림객체를 반환하면 스트림객체가 나온다
ㄴ 연결해서 연산을 이어나가기 위해서(중간연산)
-> 보통 스트림은 연속된 작업을 많이함 = 작업에 대한 목록 나열 : 메서드체이닝
-> 반환값이 스트림이 아니면 연결할 수가 없음 = 마지막 (최종연산)


예시2)

ㄴ count = 최종연산


예시3)


예시4)




스트림 활용

1. 생성하기

Collection::stream() : 일반 스트림
Arrays.stream(...) : 일반스트림 + 기본 자료형 스트림

Stream.of(T.... ) : 일반스트림, 기본 자료형 스트림




1) 특정 범위의 정수

기본 자료형 스트림 (InstStream, LongStream)

  • 횟수가 정해진 반복을 할 때 주로 사용

range(int s, int e) : s 이상 e 미만

rangeClosed(int s, int e) : s 이상 e 이하



예시)

↓ 원래는 for문써서 반복했는데 range쓰니까 코드줄었네ㅔㅔ

ㄴ 반복되는 값 잘 나온다ㅏㅏ


예시2)


예시3) predicate
반환값이 참이면 통과, 거짓이면 안내보냄


참고)

		IntStream 
			static IntStream range(시작번호, 종료 번호(미만))
								 rangeClosed(시작번호, 종료 번호(이하))
								 
								
			IntSummaryStatistics summaryStatistics()


2) 임의의 수

  • java.util.Random
  • 무한 스트림 - 갯수 제한이 필요
    • IntStream ints() : 정수범위 난수
    • LongStream longs() :
    • DoubleStream doubles() : 실수 범위 난수


3) 람다식 - iterate(), generate()

  • 무한스트림


예시) iterate()

ㄴ 매개변수ㅇ -> 연산식ㅇ
ㄴ iterate() = 무한대로 값이 출력되기 때문에 컴터 다운됨
ㄴ limit로 제한해주기


예시) generate()

ㄴ 매개변수x -> 값만 나온다
ㄴ generate() = 무한대로 값이 출력되기 때문에 컴터 다운됨
ㄴ limit로 제한해주기



4) 두 스트림의 연결 - concat()

예시)

ㄴ 2개의 스트림 만듬
ㄴ concat()통해 2개 스트림 합침
ㄴ 배열로 출력




2. 스트림의 중간 연산

1) skip(), limit()

  • limit() : 갯수 제한
  • skip() : 건너 뛰기


예시) limit()


예시) skip()

↓ 코드 줄이기 위해 메서드 참조 사용



2) filter(), distinct()

  • filter(Predicate<T> ...) : 스트림을 걸러주는 기능

    • Predicate : 판별식
  • distinct() : 중복 제거

    • 중복 제거 기준 : equals() and hashCode()


예시) filter(Predicate<T> ...)



3) sorted()

  • 정렬 : 기본 정렬 기준 java.lang.Comparable int compareTo(...) // Natural Order
  • sorted(Comparator ....)
    • 대안적인 기준 : java.util.Comparator :: int compare(....)


4) map()

  • map(Function<T,R> ...) : 변환 메서드

참고) 기본 자료형 스트림 변환 메서드

  • IntStream mapToInt(ToIntFunction<T>...)
  • LongStream mapToLong(ToLongFunction<T>...)
  • DoubleStream mapToDouble(ToDoubleFunction<T>...)


5) peek()

  • forEach와 매개변수가 동일
  • Stream peek(Consumer<T> ... ) : 중간 연산 : 중간에 값을 확인할 경우 많이 사용
  • void forEach(Consumer<T> ...) : 최종 연산 : 최종적으로 출력할때 사용


예시)



6) mapToInt(), mapToLong(), mapToDouble()




3. 스트림의 최종 연산

  • 최종 연산이 호출되어야 중간 연산도 수행, 스트림을 소비


1) forEach()



2) allMatch(), anyMatch(), noneMatch(), findFirst(), findAny()

boolean allMatch(Predicate ... ) : 전부 참인 경우 참
boolean anyMatch(Predicate ...) : 어떤 것이든 하나라도 참이면 참
boolean noneMatch(Predicate ...) : 전부 거짓일때 참
T findFirst() : 가장 첫번째 스트림의 요소를 반환



3) count(), sum(), average(), max(), min()



4) reduce()



5) collect()

Collector

java.util.stream.Collectors



6) toList(), toSet(), toMap(), toCollection(), toArray()

  • toMap() :
  • toCollection() : List, Set의 하위 클래스 객체


7) joining()



8) groupingBy(), partitioningBy()





Optional 클래스

  • JDK8

  • null에 대한 다양한 처리 방법을 제공하는 클래스

  • Wrapper 클래스

  • 목적

    • NullPointerException(NPE)은 개발자를 가장 힘들게 함... -> 예상치 못한 서비스 중단
    • 자바는 NPE에 취약한 언어...
    • 참고) 코틀린은 NPE에 해방...
    • null에 대한 다양한 처리 방식을 제공하는 클래스가 Optional 클래스
  • 특징

    • 값이 null인지 아닌지를 체크해보려면 값을 가지고 있어야 함 -> private final T value;
    • Wrapper 클래스
      ㄴ 값이 optional 객체 안에 담겨 있어야함
class Optional<T> {
	...
	private final T value;
	...
}

참고)
API 문서에서 반환값 타입 Optional 인 경우 : 결과가 null일 가능성이 있는 메서드..



예시)

ㄴ 왜 반환값 타입이 Optional일까?
ㄴ null이 발생할 수 있는 가능성이 있어 null에대한 처리를 하라고 반환값이 Optional



1. Optional 객체 생성하기

1) static Optional<T> of(T t)

  • t가 null이면 오류 발생


2) static Optional<T> ofNullable(T t)

  • t가 null이어도 오류 발생 X


예시)

예시2)

ㄴ NPE




2. Optional 객체의 값 가져오기

1) T get()

  • null 이면 오류 발생 (NoSuchElementException 발생)


2) T orElse(T other)

  • null이 아니면 값 반환, null이면 other 반환
  • 값만 기본 값으로 내보내기
    -> 값을 조금 더 가공, 처리할 필요가 있을 때 : T orElseGet(Supplier<T ... > ) 사용


예시)



3) T orElseGet(Supplier<T ... > )

  • 매개변수가 Supplier
  • 메서드(함수) 정의 : 복잡한 반환값을 생성해야 하는 경우
  • null이 아니면 값 반환
  • null이면 Supplier::get() 함수에서 생성한 값을 반환
    -> 값에 대한 변경, 코드 추가가 필요한 경우
  • 값을 조금 더 가공, 처리할 필요가 있을 때 사용 -> 함수형인터페이스


4) T orElseThrow()

  • null이면 예외 발생 (NoSuchElementException 발생)


5) T orElseThrow(Supplier<T ... > )

  • null이면 Supplier의 get() 이 발생
  • 직접 정의한 예외가 발생


예시)




3. OptionalInt, OptionalLong, OptionalDouble

  • 기본형을 처리하는 Optional 클래스
  • 오토박싱, 언박싱이 발생 X -> 성능상의 이점


1) flatMap

  • 중첩된 스트림을 -> 일차원적 스트림으로 변환
  • 중간연산


예시)

ㄴ 중첩된 스트림

ㄴ flatMap 사용

ㄴ 배열로




4. 스트림의 최종 연산

  • 최종 연산이 호출되어야 중간 연산도 수행, 스트림을 소비


1) forEach()

  • 반복 작업 수행


2) allMatch(), anyMatch(), noneMatch(), findFirst(), findAny()

① boolean allMatch(Predicate ... ) : 전부 참인 경우 참

참고) 자바스크립트 배열 객체 every와 비슷

예시)



② boolean anyMatch(Predicate ...) : 어떤 것이든 하나라도 참이면 참

참고) 자바스크립트 배열 객체 some과 비슷

예시)



③ boolean noneMatch(Predicate ...) : 전부 거짓일때 참

예시1)

예시2)



④ T findFirst() : 가장 첫번째 스트림의 요소를 반환

참고) findAny() : 병렬 스트림인 경우 가장 먼저 나오는 요소

예시)

ㄴ 100개의 무작위수를 만듬
ㄴ 100개를 무작위로 뽑아왔는데 홀수가 없는 경우도 있을 수 있음
ㄴ 그래서 findFirst()의 반환값이 옵셔널인트(null이 나올 가능성이 있다)
ㄴ orElse(-1) : 그런경우 -1이 반환되도록 설정



3) count(), sum(), average(), max(), min()

① long count() : 요소의 갯수 반환

  • 일반 트스림(Stream<T>), 기본 자료형 스트림(IntStream, LongStream, DoubleStream)


② sum() : 합계

  • 기본 자료형 스트림(IntStream, LongStream, DoubleStream) 만 있음


③ OptionalDouble average() : 평균

  • 기본 자료형 스트림(IntStream, LongStream, DoubleStream) 만 있음
  • 반환값이 OptionalDouble


④ max()

예시)



⑤ min()



4) reduce()

  • 반환값이 첫번째 매개변수로 반복해서 들어감
    -> 합계, 최대, 최소 구할때 응용됨
  • 단, 초기값이 있는 경우 초기값이 먼저 첫번째 매개변수로 들어감

예시)



5) collect()

  • Collector
  • java.util.stream.Collectors
  • 데이터 수집


5-1) toList(), toSet(), toMap(), toCollection(), toArray()

① toList()

  • 많이씀
    -> 많이쓰기 때문에 이미Stream에 정의되어 있음
    -> 원래 collector통해서 하는게 정석



예시1)

ㄴ 배열을 list형태로 바꿈

예시2)

ㄴ 많이쓰기 때문에 이미Stream에 정의되어 있음



② toSet()

  • 콜렉트를 통해 모은다음에 배열을 set형태로 바꿈
  • 많이 안써서 stream에 저으이 안되어 있음

예시)

ㄴ 배열을 set형태로 바꿈



③ toMap() : 키, 값



④ toCollection() : List, Set의 하위 클래스 객체

  • 만약 ArrayList 변환? HashSet, TreeSet로 변환? 이때는 toCollection 사용

예시)



5-2) joining()

  • 스트림 요소를 특정문자로 결합해서 문자열로 생성

예시)

ㄴ 하나의 문자열로 만듬

ㄴ "#"으로 이어붙이고 맨앞 "**", 맨뒤 "^^"



6) groupingBy(), partitioningBy()

① groupingBy() : 특정 값을 가지고 그룹

예시)

package exam01;
//// 멤버변수 정의, 생성자 정의, get() 정의, toString() 정의
public class Student {
    private int ban;
    private String name;

    public Student(int ban, String name) {
        this.ban = ban;
        this.name = name;
    }

    public int getBan() {
        return ban;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "ban=" + ban +
                ", name='" + name + '\'' +
                '}';
    }
}
package exam01;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toMap;

public class Ex08 {
    public static void main(String[] args) {
        Student [] students = {
                new Student(1, "이이름"),
                new Student(1, "김이름"),
                new Student(1, "박이름"),

                new Student(2, "이이름"),
                new Student(2, "김이름"),
                new Student(2, "박이름"),

                new Student(3, "이이름"),
                new Student(3, "김이름"),
                new Student(3, "박이름"),
        };
        /*
        Map<Integer, Student> data = Arrays.stream(students)
                .collect(toMap(Student::getBan, Student::getName));

        System.out.println(data);
         */

        Map<Integer, List<Student>> data = Arrays.stream(students)
                .collect(Collectors.groupingBy(Student::getBan));
                //.collect(Collectors.groupingBy(s -> s.getBan()));

        List<Student> students2 = data.get(2);
        students2.forEach(System.out::println);

    }
}



② partitioningBy() : 양분(참, 거짓)

  • Map<Boolean, List<...>>

예시)

package exam01;
// 멤버변수 정의, 생성자 정의, get() 정의, toString() 정의
public class Student {
    private int ban;
    private String name;

    private int score;

    public Student(int ban, String name) {
        this.ban = ban;
        this.name = name;
    }

    public Student(int ban, String name, int score) {
        this.ban = ban;
        this.name = name;
        this.score = score;
    }

    public int getScore() {
        return score;
    }

    public int getBan() {
        return ban;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "ban=" + ban +
                ", name='" + name + '\'' +
                '}';
    }
}



profile
귤귤

0개의 댓글