스트림(Stream)
- 다양한 데이터 소스(컬렉션, 배열, 임의의 수 등)를 표준화된 방법으로 다루기 위한 것
- 스트림: 데이터의 연속적인 흐름
List로 형변환을 한 Arraylist를 각각의 타입으로 스트림 생성
<스트림 사용방법>
1) 스트림 만들기
2) 중간연산(0~n번)
3) 최종연산(1번) => 결과
(1) 스트림 생성
String[] strArr = {"aaa", "bbb", "ccc"}; // (2)문자열 배열
List<String> strList = Arrays.asList(strArr); // (1)같은 내용의 문자열을 저장하는 List
(1) Stream<String> strStream1 = strList.stream();
// 스트림을 생성(collection안에 속해 있는 List로 변환한 뒤에 stream()사용)
(2) Stream<String> strStream2 = Arrays.stream(strArr);
// 스트림을 생성(Arrays를 사용해 stream에 접근해서 strArr를 stream으로)
(2) 중간연산 (3) 최종연산
strStream1.sorted().forEach(System.out::println); // (2), (3)
strStream2.sorted().forEach(System.out::println); // (2), (3)
// 스트림을 sorted()로 정렬(중간연산), forEach로 화면에 출력(최종연산)
- 중간 연산: 연산결과가 스트림인 연산. 반복적으로 적용가능
- 최종 연산: 연산결과가 스트림이 아닌 연산. 단 한 번만 적용가능(스트림의 요소를 소모)
-> 중간 연산은 연산결과를 스트림으로 반환하기 때문에 중간 연산을 연속해서 연결할 수 있다. (점으로 연결해서 메서드를 사용하는 것을 뜻함 연산결과가 계속해서 스트림이기 때문에)
1) 스트림생성 2) 중간연산(distinct( ):중복 제거 / limit(5):5개 자르기 / sorted():정렬) 3) 최종연산 1번(sysout 출력)
스트림의 특징
1) 스트림은 데이터 소스(원본)로부터 데이터를 읽기 만할 뿐 변경하지 않는다.(Read only)
2) 스트림은 Iterator처럼 일회용이다.(필요시 다시 스트림 생성)
-> 최종연산이 되면 요소가 소모되기 때문에 기존의 Stream을 사용할 수 없음
3) 최종연산 전까지 중간연산이 수행되지 않는다. – 지연된 연산
-> 스트림에는 무한스트림과 유한스트림이 있다.
-> 스트림이 중간연산을 즉각적으로 하는게 아니라 스트림을 가지고 어떤 작업을 해야 하는 지 확인만 해 둠(중간연산 바로 실행 xx) -> 무한 스트림이기 때문
4) 스트림은 작업을 내부 반복으로 처리한다.
- 내부반복: 반복문을 메서드의 내부에 숨길 수 있다는 것을 의미함
-> forEach()는 for문을 아래 코드처럼 메서드 안에 넣어 버림(코드가 간결해짐)
5) 스트림의 작업을 병렬로 처리한다. – 병렬스트림
-> 스트림에 .parallel( )이라는 메서드 호출 -> 병렬로 연산을 수행하도록 함
-> 반대로 병렬로 처리되지 않게 하려면 sequential( )(parallel()을 호출한 것을 취소할 때만 사용)
- 기본형 스트림 : IntStream, LongStream, DoubleStream
- 오토박싱&언박싱의 비효율이 제거됨(Stream<Integer>대신 IntStream사용: 데이터 소스가 기본형 일 때만)
- 숫자와 관련된 유용한 메서드를 Stream<T>보다 더 많이 제공
-> Stream<Integer>: 스트림의 요소가 Integer
-> Stream변환 하면 기본형 -> 참조형으로 바뀌게 됨( 1 -> new Integer(1))
스트림만들기
1. 컬렉션
- Collection 인터페이스의 stream( )으로 컬렉션을 스트림으로 변환
-> Collection의 자손인 List와 Set을 구현한 컬렉션 클래스들은 모두 이 메서드로 스트림을 생성할 수 있다.
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> intStream = list.stream(); // list를 데이터 소스로 하는 새로운 스트림을 생성
// 스트림의 모든 요소를 출력
intStream.forEach(System.out::print); // 12345 forEach()최종연산
intStream.forEach(System.out::print); // 에러! stream has already been operated upon or Closed(스트림은 일회용이기 때문)
// 스트림은 일회용. 스트림에 대해 최종연산을 수행하면 stream이 닫힌다.
intStream = list.stream(); // 스트림 다시 생성
intStream.forEach(System.out::print); // 12345
2.배열
1) 객체 배열로부터 스트림 생성하기
Stream<T> Stream.of(T... values) // 가변인자
Stream<T> Stream.of(T[])
Stream<T> Arrays.stream(T[])
Stream<T> Arrays.stream(T[] array, int startInclusive, int endExclusive) // from ~ to
Stream<String> strStream = Stream.of("a","b","c"); // 가변인자
Stream<String> strStream = Stream.of(new String[] {"a","b","c"});
Stream<String> strStream = Arrays.stream(new String[] {"a","b","c"});
Stream<String> strStream = Arrays.stream(new String[] {"a","b","c"},0,3);
2) 기본형 배열로부터 스트림 생성하기
IntStream IntStream.of(int... values) // Stream이 아니라 IntStream
IntStream IntStream.of(int[])
IntStream Arrays.stream(int[])
IntStream Arryas.stream(int[] array, int startInclusive, int endExclusive)
예제)
Stream<String> strStream = Stream.of("a","b","c");
strStream.forEach(System.out::print); // abc
String[] strArr = {"A","B","C"};
Stream<String> strStream1 = Stream.of(strArr);
Stream<String> strStream2 = Stream.of(new String[] {"A","B","C"});
strStream1.forEach(System.out::print); // ABC
strStream2.forEach(System.out::print); // ABC
int[] intArr = {1,2,3,4,5};
IntStream intStream = Arrays.stream(intArr); // 기본형스트림IntStream
intStream.forEach(System.out::print); // 12345
System.out.println("sum=" + intStream.sum()); // sum외에도 average등도 있음
//System.out.println("count=" + intStream.count());
Integer[] intArr1 = {1,2,3,4,5};
Stream<Integer> intStream1 = Stream.of(intArr1); // Integer객체Stream
intStream1.forEach(System.out::print); // 12345
3. 임의의 수
- 난수를 요소로 갖는 스트림 생성하기
- 이 메서드들이 반환하는 스트림은 크기가 정해지지 않은 ‘무한스트림(infinite stream)’이므로 limit()도 같이 사용해서 스트림의 크기를 제한해 주어야 한다.
-> limit()은 스트림의 개수를 지정하는데 사용되며, 무한스트림을 유한스트림으로 만들어준다.
IntStream intStream = new Random().ints(); // 무한 스트림
intStream.limit(5).forEach(System.out::println); // 5개의 요소(중간연산)만 출력(최종연산)한다.
예제)
IntStream intStream1 = new Random().ints(); // 크키가 5인 난수 스트림 반환
intStream1.limit(5).forEach(System.out::println); // 무한스트림에서 5개의 요소 출력
IntStream intStream2 = new Random().ints(10,1,10); // 크기가 10인 1~9까지의 난수 생성
intStream2.forEach(System.out::println);
IntStream intStream3 = new Random().ints(1,10); // 1~9까지의 난수 생성
intStream3.limit(10).forEach(System.out::println); // 크기를 10으로 설정
4. 특정 범위의 정수
- 특정 범위의 정수를 요소로 갖는 스트림 생성하기(IntStream, LongStream)
IntStream intStream = IntStream.range(1, 5); // 1,2,3,4
IntStream intStream1 = IntStream.rangeClosed(1, 5); // 1,2,3,4,5 끝이 포함
5. 람다식 iterate( ), generate( )
- 람다식을 소스로 하는 스트림 생성하기
- generate( )도 Iterate( )처럼, 람다식에 의해 계산되는 값을 요소로 하는 무한 스트림을 생성(limit 값으로 잘라줘야 함)
-> iterate( )는 이전 요소를 seed(초기값)로 해서 다음 요소를 계산한다.
-> generate()는 seed(초기값)를 사용하지 않는다.
//iterate(T Seed, UnaryOperator f) 단항 연산자(값을 하나 넣으면 하나 나옴)
Stream<Integer> intStream1 = Stream.iterate(2, n -> n + 2); // 2부터 짝수스트림(10개)
intStream1.limit(10).forEach(System.out::println);
Stream<Integer> intStream2 = Stream.iterate(1, n -> n+2); //1부터 홀수스트림(10개)
intStream2.limit(10).forEach(System.out::println);
// generate(Suppliers s): 주기만 하는 것 입력 x 출력O
Stream<Integer> oneStream = Stream.generate(()->1); // 1만 10번 출력
oneStream.limit(10).forEach(System.out::println);
6. 파일과 빈 스트림
- 파일을 소스로 하는 스트림 생성하기
- 비어있는 스트림 생성하기
Stream emptyStream = Stream.empty( ); // empty( )는 빈 스트림을 생성해서 반환한다.
long count = emptyStream.count( ); // count의 값은 0
'멀티캠퍼스 풀스택 과정 > Java의 정석' 카테고리의 다른 글
자바의 정석11-5 스트림의 연산(최종연산) (0) | 2022.02.02 |
---|---|
자바의 정석11-4 스트림의 연산(중간연산과 Optioanl<T>) (0) | 2022.01.16 |
자바의 정석11-2 java.util.Function 패키지의 함수형 인터페이스와 메서드 참조 (0) | 2022.01.16 |
자바의 정석11-1 람다와 함수형인터페이스 (0) | 2022.01.16 |
자바의 정석10-5 쓰레드의 동기화(Synchronization) (0) | 2022.01.13 |