스트림(stream)
: 다양한 데이터소스를 표준화된 방법으로 다루기 위한 것
데이터 소스를 추상화하고, 데이터를 다루는데 자주 사용되는 메소드들을 정의해 놓음
(데이터 소스가 무엇이던 간에 같은 방식으로 다룰 수 있게 됨)
배열이나 컬렉션뿐만 아니라 파일에 저장된 데이터도 모두 같은 방식으로 다룰 수 있음
String[] strArr = { "aaa", "ddd", "ccc" };
List<String> strList = Arrays.asList(strArr);
Stream<String> strStream1 = strList.stream(); //스트림을 생성
Stream<String> strStream2 = Arrays.stream.(strArr); //스트림을 생성
// 두 스트림의 데이터 소스는 서로 다르지만, 정렬하고 출력하는 방법은 완전 동일
strStream1.sorted().forEach(System.out::println);
strStream2.sorted().forEach(System.out::println);
스트림의 특징
- 데이터 소스로 부터 데이터를 읽기만 할 뿐, 데이터 소스를 변경하지 않음
- 일회용
( 한번 사용하면 닫혀서 다시 사용할 수 없음 필요하면 다시 스트림을 생성해야함)
- 작업을 내부 반복으로 처리함 (반복문을 메소드의 내부에 숨김)
void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action); //매개변수의 널 체크
for(T t : src) { //내부반복(for문을 메소드안으로 넣음)
action.accept(T);
}
}
- 지연된 연산
최종 연산이 수행되어야 비로소 스트림의 요소들이 중간 연산을 거쳐 최종 연산에서 소모됨
- Stream<Integer>와 IntStream
오토박싱&언박싱으로 인한 비효율을 줄이기 위해 데이터 소스의 요소를 기본형으로 다루는 스트림, IntStream,LongStream, DoubleStream이 제공됨
- 병렬 처리가 쉽다
스트림에 parallel( )메소드 호출하면 병렬로 연산을 수행함
sequential( )을 호출해서 parallel( )호출한거 취소 가능
스트림 만들기
컬렉션의 최고 조상인Collection에 stream( )이 정의되어 있음
Collection의 자손인 List와 Set을 구현한 컬렉션 클래스들은 모두 이 메소드로 스트림 생성가능
List<Integer> list = Arrays.asList(1,2,3,4,5); // 가변인자
Stream<Integer> intStream = list.stream(); //list를 소스로 하는 스트림 생성
// forEach( )는 지정된 작업을 스트림의 모든 요소에 대해 수행함
intStream.forEach(System.out::println); //스트림의 모든 요소를 출력
intStream.forEach(System.out::println); //에러! 스트림이 이미 닫혔음
forEach( )가 스트림의 요소를 소모하면서 작업을 수행하므로, 같은 스트림에 forEach( )를 두 번 호출 불가!!
스트림의 요소를 한번 더 출력하려면 스트림을 새로 생성해야 함
스트림 만들기_배열
Stream과 Arrays에 static메소드로 정의되어 있음
Stream<T> Stram.of(T...values) //가변인자
Stream<T> Stream.of(t[])
Stream<T> Arrays.stream(T[])
Stream<T> Arrays.stream(T[] array, int startInclusive, int endExclusive)
기본형 배열을 소스로 하는 스트림을 생성하는 메소드
IntStream IntStream.of(int...values) // Stream이 아니라 IntStream
IntStream IntStream.of(int[])
IntStream Arrays.stream(int[])
IntStream Arrays.stream(int[] array, int startInclusive, int endExclusive)
스트림 만들기_임의의 수
Random클래스에는 해당 타입의 난수들로 이루어진 스트림을 반환하는 메소드들이 포함되어 있음
IntStream ints( )
LongStream longs( )
DoubleStream doubles( )
이 메소드들이 반환하는 스트림은 크기가 정해지지 않은 '무한 스트림' 이여서 limit( )도 같이 사용해서 스트림 크기를 제한해 주어야 함
IntStream intStream = new Random().ints(); // 무한 스트림
intStream.limit(5).forEach(System.out::println); // 5개의 요소만 출력
매개변수로 스트림의 크기를 지정해서 유한 스트림을 반환하는 메소드는 limit( )을 사용하지 않아도 됨
IntStream ints( long streamSize )
LongStream longs( long streamSize )
DoubleStream doubles( long streamSize )
스트림 만들기_특정 범위의 정수
지정된 범위의 연속된 정수를 스트림으로 생성해서 반환하는 메소드
IntStream IntStream.range(int begin, int end)
IntStream IntStream.rangeClosed(int begin, int end)
range( )의 경우, 경계의 끝인 end가 범위에 포함X,
rangeClosed( )의 경우 경계의 끝인 end가 범위에 포함됨
IntStream intStream = IntStream.range(1,5); // 1,2,3,4
IntStream intStream = IntStream.rangeClosed(1,5); //1,2,3,4,5
스트림 만들기_ 람다식 iterate( ), generate( )
Stream클래스의 iterate( )와 generate( )은 람다식을 매개변수로 받아, 이 람다식에 의해 계산되는 값들을 요소로 하는 무한 스트림을 생성함
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
static <T> Stream<T> generate(Supplier<T> s)
iterate( )은 seed(씨앗값)으로 지정된 값부터 시작해서, 계산된 결과를 다시 seed값으로 해서 계산을 반복함
generate( )은 seed를 사용하지 않고 람다식에 의해 계산된는 값을 요소로 하는 무한 스트림을 생성
!주의!
iterate( )와 generate( )에 의해 생성됨 스트림을 기본형 스트림 타입의 참조변수로 다룰 수 없음
IntStream evenStream = Stream.iterate(0, n->n+2); // 에러
DoubleStream randomStream = Stream.generate(Math::random); // 에러
스트림 만들기_파일과 빈 스트림
list( )는 지정된 디렉토리(dir)에 있는 파일 목록을 소스로 하는 스트림을 생성해서 반환함
스트림에 연산을 수행한 결과가 하나도 없을 때는 null보다 빈 스트림을 반환하는 것이 더 나음
Stream emptyStream = Stream.empty(); //empty()빈 스트림을 생성해서 반환한다
long count = emptyStream.count(); //count의 값은 0
스트림의 연산
: 스트림에 정의된 메소드 중에서 데이터 소스를 다루는 작업을 수행하는 것을 연산(operation)이라고 함
중간연산 : 연산 결과가 스트림인 연산. ( 스트림에 연속해서 중간 연산할 수 있음 )
최종연산 : 연산 결과가 스트림이 아닌 연산.( 스트림의 요소를 소모함, 단 한번만 가능)
<중간 연산>
일부 잘라내기 skip( ), limit( )
Stream<T> skip(long n) //앞에서부터 n개 건너뛰기
Stream<T> limit(long maxSize) //maxSize이후의 요소는 잘라냄
IntStream intStream = IntStream.rangeClosed(1,10); // 1~10의 요소를 가진 스트림
intStream.skip(3).limit(5).forEach(System.out::print); //45678
제거,제외하기 filter( ), distinct( )
Stream<T> filter(Predicate<? super T> predicate) //주어진 조건(Predicate)에 맞지않는 요소를 걸러냄
Stream<T> distinct() //스트림에서 중복된 요소들을 제거
Optional<T>
: T타입의 객체를 감싸는 래퍼 클래스
Optional타입의 객체에는 모든 타입의 객체를 담을 수 있음
null 체크를 위한 if문 없이도 NullPointerException이 발생히지 않음
Optional객체를 생성할 때는 of( )또는 ofNullable( )을 사용
참조변수의 값이 null일 가능성이 있으면, of( )대신 ofNullable( )을 사용해야함
(of( )는 매개변수의 값이 null이면 NullPointerException발생함)
Optional<T>타입의 참조변수를 기본값으로 초기화할 때는 empty( )를 사용
Optional<String> optVal = Optional.of(null); //NullPointerException발생
Opional<String> optVal = Optional.ofNullable(null); //OK
Optional<String> optVal = Null; //널로 초기화. 바람직하지 않음
Optional<String> optVal = Optional.<String>empty(); // 빈 객체 초기화
Optional객체에 저장된 값을 가져올 때는 get( )을 사용
값이 null일 때는 orElse( )로 NoSuchElementException이 발생하는걸 막을 수 있음
Optional<String> optVal = Optional.of("abc");
String str1 = optVal.get(); // optVal에 저장된 값을 반환. null이면 예외발생
String str2 = optVal.orElse(""); // optVal에 저장된 값이 null일 때는, ""를 반환
기본형 값을 감싸는 래퍼클래쓰
IntStream과 같은 기본형 스트림의 최종 연산의 일부는 Optional대신 기본형을 값으로 하는 OptionalInt, OptionalLong, OptionalDouble을 반환함
<최종연산>
'TIL (Today I Learned) > Java' 카테고리의 다른 글
ASCII(아스키) (1) | 2023.03.28 |
---|---|
TIL 230324(금) 네트워크 (6) | 2023.03.24 |
TIL 230321(화) 람다식, 함수형 인터페이스, 메소드 참조 (8) | 2023.03.21 |
TIL 230320(월) 쓰레드, 데몬 쓰레드, 쓰레드 스케줄링, 쓰레드 동기화 (6) | 2023.03.20 |
TIL 230319(일) (3) | 2023.03.19 |
댓글