Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 자바의 정석 기초편 ch4
- 자바의 정석 기초편 ch2
- @Aspect
- 자바의 정석 기초편 ch5
- 자바의 정석 기초편 ch9
- 스프링 고급 - 스프링 aop
- 스프링 mvc2 - 타임리프
- jpa 활용2 - api 개발 고급
- 자바의 정석 기초편 ch12
- 자바의 정석 기초편 ch14
- 코드로 시작하는 자바 첫걸음
- 자바의 정석 기초편 ch3
- 자바의 정석 기초편 ch7
- 자바의 정석 기초편 ch11
- 스프링 mvc1 - 스프링 mvc
- 스프링 db2 - 데이터 접근 기술
- 스프링 mvc2 - 검증
- jpa - 객체지향 쿼리 언어
- 자바의 정석 기초편 ch6
- 자바의 정석 기초편 ch13
- 2024 정보처리기사 수제비 실기
- 스프링 mvc1 - 서블릿
- 자바의 정석 기초편 ch1
- 자바의 정석 기초편 ch8
- 스프링 mvc2 - 로그인 처리
- 게시글 목록 api
- 타임리프 - 기본기능
- 스프링 입문(무료)
- 2024 정보처리기사 시나공 필기
- 스프링 db1 - 스프링과 문제 해결
Archives
- Today
- Total
나구리의 개발공부기록
자바의 정석 기초편 ch14 - 15 ~ 22[스트림, 스트림의 특징, 스트림 만들기] 본문
유튜브 공부/JAVA의 정석 기초편(유튜브)
자바의 정석 기초편 ch14 - 15 ~ 22[스트림, 스트림의 특징, 스트림 만들기]
소소한나구리 2023. 12. 20. 16:301) 스트림(Stream)
- Java8부터 적용됨
- 데이터의 연속적인 흐름, 즉 메서드 체인 방식으로 데이터들의 연산결과를 반환
- 다양한 데이터 소스(컬렉션, 배열)를 표준화된 방법으로 다루기 위하여 나옴
(1) 동작 방식
- 데이터소스 [컬렉션(List,Set,Map), 배열]
- Stream 생성
- 중간연산(여러번)
- 최종연산(한번)
- 결과반환
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> intStream = list.stream(); // 컬렉션
Stream<String> strStream = Stream.of(new String[]{"a", "b", "c"}); // 배열
Stream<Integer> evenStream = Stream.iterate(0, n -> n + 2); // 0,2,4,6, ...
Stream<Double> randomStream = Stream.generate(Math::random); // 랜덤수
IntStream intStreamRandom = new Random().ints(5); // 난수 스트림(크기가 5)
(2) 스트림이 제공하는 기능
- 중간 연산 : 연산결과가 스트림인 연산, 반복적으로 사용 가능
- 최종 연산 : 연산결과가 스트림이 아닌 연산. 단 한번만 적용 가능(스트림의 요소를 소모함)
2) 스트림의 특징
(1) 데이터 소스로부터 데이터를 읽기만 함
- 스트림은 읽기 전용이기 때문에 데이터를 저장할 수 없음
- 즉, 스트림의 연산결과는 원본에 영향을 주지않고 연산한 결과를 담기위해선 새로운 참조변수가 필요함
List<Integer> list = Arrays.asList(3,1,5,4,2);
List<Integer> sortedList = list.stream().sorted()
.collect(Collectors.toList()); // 새로운 List에 저장
System.out.println(list); // [3, 1, 5, 4, 2]
System.out.println(sortedList); // [1, 2, 3, 4, 5]
(2) 일회용
- Iterator처럼 일회용이기 때문에 최종연산으로 스트림을 소모하면 다시 스트림을 생성해야함
- 즉 재사용이 불가능함
strStream.forEach(System.out::println); // 모든 요소를 화면에 출력(최종연산)
int numOfStr = strStream.count(); // 에러. 스트림이 이미 닫혔음.
(3) 지연된 연산
- 스트림의 중간연산은 기본적으로 순서대로 연산을 하지만 당장 수행을 할 수 없을경우에는 연산을 지연시킨 후 연산을 적용할 수 있을 때 연산을 적용함
- 최종 연산 전까지 지연된연산까지 모든 연산을 마친 후에 최종 연산 결과를 반환함
- 무한정으로 스트림의 요소가 제공되는 무한 스트림을 아래처럼 중간연산의 순서로 작성하면 distinct로 중복을 제거할 수 없어 동작이 안할 것 같지만, 스트림은 지연된 연산을 제공하기 때문에 해당 연산을 지연 시긴 후 다른 중간연산부터 수행함
- 가능한 중간연산이 수행되고 나서 지연된 연산을 다시 수행하고 모든 연산이 완료되면 최종 연산을 반환함
- 즉, 중간연산은 순서에 관계없이 적용하고 싶은 연산을 모두 입력해면 됨 -> 장점
IntStream intStream = new Random().ints(1, 46); // 1~45범위의 무한 스트림
intStream.distinct() // 중간 연산
.limit(6) // 중간 연산
.sorted() // 중간 연산
.forEach(i->System.out.print(i+",")); // 최종 연산
(4) 반복처리
- 스트림은 forEach()메서드(최종연산)로 간단하게 요소를 반복할 수 있음
- 성능은 조금 떨어질 수 있지만 코드가 매우 간결해지기때문에 자주 사용됨
// 일반 적인 반복문
for (String str : strList)
System.out.println(str);
// stream의 forEach로 요소를 반복해서 출력
stream.forEach(System.out::println);
// forEach의 구조
void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action); // 매개변수의 널 체크
for (T t : src) // 내부 반복 (for문을 메서드 안으로 넣음)
action.accept(T);
}
(5) 병렬 처리
- 병렬스트림으로 전환하는 .parallel()메서드로 멀티 쓰레드로 처리할 수 있음
Stream<String> strStream = Stream.of("dd", "aaa", "CC", "cc", "b");
int sum = strStream.parallel() // 병렬 스트림으로 전환(속성만 변경)
.mapToInt(s -> s.length()).sum(); // 모든 문자열의 길이의 합
(6) 기본형 스트림
- IntStream, LongStream, DoubleStream
- 오토박싱&언박싱의 비효율이 제거 됨 (Stream<Integer> 대신 intStream을 사용)
- 데이터 소스가 기본형일때 사용 가능 하며 스트림 변환시 참조형으로 변환이 되는데 데이터가 많으면 효율이 떨어져 기본형스트림을 제공함
- 숫자와 관련된 유용한 메서드를 Stream<T>보다 더 많이 제공 (sum(), count(), average()... 등등)
3) 스트림 만들기(스트림 생성)
- Collection인터페이스의 stream()으로 컬렉션을 스트림으로 변환할 수 있음
Stream<E> stream() // Collection인터페이스의 메서드 (list, set에서 사용가능)
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> intStream = list.stream(); // list를 stream()으로 변환(스트림 생성)
// 스트림의 모든 요소를 출력
intStream.forEach(System.out::print); // 12345 forEach(메서드 참조)
intStream.forEach(System.out::print); // 한번더? forEach는 최종연산 -> 에러. 스트림이 이미 종료
(1) 객체 배열로부터 스트림 생성
- Stream.of(T... values) : 인수의 값을 직접 입력하여 스트림을 생성, 가변 인자이기 때문에 원하는 만큼 입력할 수 있음
- Arrays.strea(T[]) : 인수로 배열을 입력(생성)해야하며, 2번째(from) ~ 3번째(to, to는 범위에 미포함)까지의 범위를 지정할 수 있음
// Stream.of()
Stream<String> strStream = Stream.of("a","b","c"); // 가변 인자
Stream<String> strStream = Stream.of(new String[]{"a","b","c"});
// Arrays.stream()
Stream<String> strStream = Arrays.stream(new String[]{"a","b","c"});
// from ~ to (to는 미포함 = 0,1,2 까지만 생성)
Stream<String> strStream = Arrays.stream(new String[]{"a","b","c"}, 0, 3);
(2) 기본형 배열로부터 스트림 생성
- 생성 방식은 동일함
IntStream IntStream.of(int... values) // 가변인자
IntStream IntStream.of(int[])
IntStream Arrays.IntStream(int[])
// from ~ to (to는 미포함)
IntStream Arrays.IntStream(int[] array, int from, int to)
(3) 배열 스트림 예제
public class Ex14_StreamArr {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5);
// list를 데이터 소스로 하는 새로운 스트림 생성
Stream<Integer> intStream = list.stream();
intStream.forEach(System.out::print); // 출력
intStream = list.stream(); // Stream을 재생성(일회성이기 때문에 새로 생성해야함)
intStream.forEach(System.out::print); // 재출력
System.out.println();
// of(), 가변인자로 스트림 생성
Stream<String> strStream = Stream.of("a","b","c");
strStream.forEach(System.out::println);
// of(), 스트링 배열을 생성하여 스트림을 생성
Stream<String> strStream2 = Stream.of(new String[] {"a","b","c"});
strStream2.forEach(System.out::println);
// stream(), 스트링 배열을 생성하여 스트림을 생성
Stream<String> strStream3 = Arrays.stream(new String[] {"a","b","c"});
strStream3.forEach(System.out::println);
// stream(), 인트 배열을 인수로 스트림을 생성
// 숫자타입은 기본형스트림을 사용하면 편리함, 성능면에서 장점이 있음
int[] intArr = {1,2,3,4,5};
IntStream intStream2 = Arrays.stream(intArr);
intStream2.forEach(System.out::println); // 그냥 출력
// forEach외 다른 최종연산들
intStream2 = Arrays.stream(intArr);
System.out.println("intStream2의 count = "+intStream2.count());
intStream2 = Arrays.stream(intArr);
System.out.println("intStream2의 sum = "+intStream2.sum());
intStream2 = Arrays.stream(intArr);
System.out.println("intStream2의 average = "+intStream2.average());
// Integer배열로 기본형이아닌 참조형 스트림을 생성, max, sum등의 숫자관련 편의메서드를 사용할 수 없음
Integer[] intArr2 = {1,2,3,4,5};
Stream<Integer> intStream3 = Arrays.stream(intArr2);
intStream3.forEach(System.out::println);
}
}
(4) 난수를 요소로 갖는 스트림 생성
- Random클래스에는 int, long, double타입의 난수를 생성하는 메서드를 가지고 있어 해당 메서드들을 활용하여 난수를 요소로 갖는 스트림을 생성할 수 있음
- ints() : Integer 타입 난수 생성(Integer 범위)
- longs() : Long 타입 난수 생성(Long 범위 )
- doubles() : Doublec 타입 난수 생성(0.0이상 1.0미만)
IntStream intStream = new Random().ints(); // 무한 스트림
// 무한스트림은 limit()로 자르거나, 무한스트림을 생성하는 메서드에 크기를 지정해 줘야함.
intStream.limit(5).forEach(System.out::println); // 5개의 요소만 출력한다.
IntStream intStream = new Random().ints(5); // 크기가 5인 난수 스트림을 반환
// Random()클래스에 정의되어있는 메서드들 - 아래의 메서드들은 무한스트림을 생성함
Integer.MIN_VALUE <= ints() <= Integer.MAX_VALUE
Long.MIN_VALUE <= longs() <= Long.MAX_VALUE
0.0 <= doubles() < 1.0
// 무한 스트림, begin ~ end(미포함) 범위의 난수를 생성
IntStream ints(int begin, int end)
LongStream longs(long begin, long end)
DoubleStream doubles(double begin, double end)
// 유한 스트림, 난수의 생성 개수를 지정할 수 있음
IntStream ints(long streamSize, int begin, int end)
LongStream longs(long streamSize, long begin, long end)
DoubleStream doubles(long streamSize, double begin, double end)
(6) 난수 스트림 예제
- 중간연산인 limit()혹은 난수를 생성하는 메서드에 인수를 하나만 입력하여 스트림의 개수를 지정
- 메서드의 인수에 2개를 입력하면 범위를 지정할 수 있음(2번째 인수의 값은 포함되지 않음)
- 메서드의 인수에 3개를 입력하면 개수, 범위를 모두 지정할 수 있음(범위는 위와 동일)
public class Ex14_StreamRandom {
public static void main(String[] args) {
// 무한스트림 개수지정 - limit
IntStream intStream = new Random().ints();
intStream.limit(3).forEach(System.out::println);
System.out.println("-----------------------------------------------------");
// 무한스트림 개수지정 - ints(size)
IntStream intStream2 = new Random().ints(7);
intStream2.forEach(System.out::println);
System.out.println("-----------------------------------------------------");
// 무한스트림 범위지정 - ints(from, to)
IntStream intStream3 = new Random().ints(1, 10);
intStream3.limit(5).forEach(System.out::println);
System.out.println("-----------------------------------------------------");
// 유한스트림 개수,범위지정 - ints(출력개수, from, to)
IntStream intStream4 = new Random().ints(5, 10, 20);
intStream4.forEach(System.out::println);
}
}
(7) 정수를 요소로 갖는 스트림 생성
- InteStream과 LongStream의 range()를 사용하면 특정 범위의 정수를 갖는 스트림을 생성할 수 있음
- 두번째 인수의 값을 미포함, 포함하는 메서드가 모두 존재함
IntStream IntStream.range(int begin, int end) // from ~ to(to 미포함)
IntStream IntStream.rangeCloed(int begin, int end) // from ~ to(to 포함)
IntStream intStream = IntStream.range(1, 5); // 1,2,3,4
IntStream intStream = IntStream.rangeClosed(1, 5); // 1,2,3,4,5
(8) 람다식을 소스로 하는 스트림 생성
- iterate()는 이전 요소를 seed로 해서 다음 요소를 계산 즉, 입력된값을 받아서 계산
- generate()는 seed를 사용하지 않아 독립적으로 계산함
// 무한스트림 - limit으로 개수 설정 해줘야함
static <T> Stream<T> iterate(T seed,UnaryOperator<T> f) // 이전 요소에 종속적(T seed = 초기값)
static <T> Stream<T> generate(Supplier<T> s) // 이전 요소에 독립적
// iterate - 앞의 결과를 가지고 다음결과가 나옴
Stream<Integer> evenStream = Stream.iterate(0, n->n+2); // 0,2,4,6, ...
// generate - 이전 결과가 전혀 상관 없음
Stream<Double> randomStream = Stream.generate(Math::random); // 난수
Stream<Integer> oneStream = Stream.generate(()->1); // 계속 1이 찍힘
(9) 람다식 스트림 실습
public class Ex14_StreamLambda {
public static void main(String[] args) {
// iterate(T seed, UnaryOperator f) : 단항연산자
// iterate() 무한스트림 출력, seed값을 받아서 람다식의 연산을 수행
Stream<Integer> intStream = Stream.iterate(1, n -> n + 2);
intStream.limit(10).forEach(System.out::println);
// generate(Supplier s) : 주기만 하는것 입력x, 출력O
// generate() 무한스트림 출력, 입력값이 없음
Stream<Integer> intStream2 = Stream.generate(() -> 1);
intStream2.limit(10).forEach(System.out::println);
}
}
(10) 파일을 소스로 하는 스트림 생성
- Files의 list나 lines로 값을 파일이나 파일의 내용을 스트림으로 생성할 수 있음
Stream<Path> Files.list(Path dir) // Path는 파일 또는 디렉토리
// 파일 내용을 라인 단위로 읽어서 String Stream 으로 만듦
Stream<String> Files.lines(Path path)
Stream<String> Files.lines(Path path, Charset cs)
Stream<String> lines() // BufferedReader클래스의 메서드(15장, 강의에없음)
(11) 비어있는 스트림 생성
- Stream.empty()로 비어있는 스트림을 생성
Stream emptyStream = Stream.empty();
long count = emptyStream.count();
** 출처 : 남궁성의 정석코딩_자바의정석_기초편 유튜브
'유튜브 공부 > JAVA의 정석 기초편(유튜브)' 카테고리의 다른 글
자바의 정석 기초편 ch14 - 35 ~ 44 [Optional, 최종연산(reduce까지)] (0) | 2023.12.22 |
---|---|
자바의 정석 기초편 ch14 - 23 ~ 34[스트림의 연산들, 스트림의 중간연산] (1) | 2023.12.21 |
자바의 정석 기초편 ch14 - 7 ~ 14[java.util.function패키지, Predicate의 결합, CF와 함수형 인터페이스, 메서드 참조, 생성자의 메서드 참조] (1) | 2023.12.20 |
자바의 정석 기초편 ch14 - 1 ~ 6 [람다식이란?, 람다식 작성하기, 함수형 인터페이스] (0) | 2023.12.19 |
자바의 정석 기초편 ch13 - 33 ~ 36 [쓰레드의 동기화, wait(), notify()] (0) | 2023.12.19 |