2019-04-30 [java-study] java8 스트림
30 Apr 2019 | java stream스트림 API
스트림이란?
: 데이터를 추상화하여 다루어 다양한 방식으로 저장된 데이터를 읽고 쓰기 위한 방법
- List, 배열의 iterator나 반복문 사용의 코드 길이가 매우 길고 재사용 힘듦 => 해결책
특징
- 외부 반복을 통해 작업하는 컬렉션과는 달리 내부 반복을 통해 작업을 수행함
- 내부 반복이라는 것은 반복문을 메서드의 내부에 숨길 수 있다는 것을 의미
-
재사용이 가능한 컬렉션과는 달리 단 한 번만 사용할 수 있음.
-
원본 데이터를 변경하지 않음.
-
스트림의 연산은 필터-맵 기반의 API를 사용하여 지연연산을 통해 성능을 최적화함.
-
parallelStream() 메소드를 통한 손쉬운 병렬 처리를 지원함.
- 여러쓰레드가 처리해주니 병렬스트림이 항상 성능면에서 유리해보일 수 있지만 애플리케이션에서 사용하는 쓰레드가 많거나 스트림의 요소 수가 많지 않다면 오히려 쓰레드를 사용하는데 드는 오버헤드가 더 클 수도 있다
동작 흐름
데이터 소스 => 중개연산(필터) - 스트림의 변환 => 중개 연산(맵) - 스트림의 사용=> 최종 연산
스트림 생성
- 컬렉션
ArrayList<Integer> list = new ArrayList<>();
list.add(4);
list.add(3);
list.add(2);
list.add(1);
Stream<Integer> stream = list.stream();
stream.forEach(System.out::println);
forEach() => 스트림의 요소를 하나씩 소모하면서 순차적 접근 (원본 데이터는 그대로 유지)
- 배열
String[] arr = new String[]{"하나", "둘", "셋", "넷"};
Stream<String> stream1 = Arrays.stream(arr);
stream1.forEach(e->System.out.print(e+" ")); //하나 둘 셋 넷
Stream<String> stream2 = Arrays.stream(arr, 1, 3); //subString
stream2.forEach(e -> System.out.print(e+" ")); //둘 셋
-> 컬렉션과 차이 배열의 특정 부분만 이용할 수 있음.
Int, long 타입이 있는 Stream은 Stream 앞에 타입을 적어준다 ex) IntStream, LongStream…
- 가변 매개변수
Stream<Double> stream = Stream.of(4.2, 2.5, 3.1, 1.9);
stream.forEach(System.out::println);
of() 메소드를 사용하여 가변 매개변수를 전달받아 스트림 생성 가능
- 지정된 범위의 연속된 정수
range(), rangeClosed()
- range() : 시작 정수를 포함하지만, 명시된 마지막 정수는 포함하지 않는 스트림
- rangeClosed() : 작 정수뿐만 아니라 명시된 마지막 정수까지도 포함하는 스트림을 생성
IntStream stream1 = IntStream.range(1, 4);
stream1.forEach(e -> System.out.print(e + " ")); //1부터 4이전까지 1 2 3
IntStream stream2 = IntStream.rangeClosed(1, 4);
stream2.forEach(e -> System.out.print(e + " ")); //1부터 4까지 1 2 3 4
- 람다 표현식
- iterate() : 시드로 명시된 값을 람다 표현식에 사용하여 반환된 값을 다시 시드로 사용하는 방식으로 무한 스트림을 생성
- 이해하기 어렵 -> 예제
IntStream stream = Stream.iterate(2, n -> n+2);//2,4,6,...
Stream.iterate(0, n -> n + 1)
.limit(10) //조건
.forEach(x -> System.out.println(x)); //0,1,2,...,9
- generate()
Stream<String> stream = Stream.generate(() -> "Echo").limit(5);
stream.forEach(System.out::println); //echo 5번
- 빈 스트림
Stream<Object> stream = Stream.empty();
System.out.println(stream.count()); // 스트림의 요소의 총 개수를 출력함.
-> 말그대로 빈 스트림
스트림의 중개 연산
- 스트림 필터링
- distinct() : 스트림에서 중복 요소 제거 (equal() 기준)
- filter() : 말 그대로 필터링
IntStream stream1 = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);
IntStream stream2 = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);
// 스트림에서 중복된 요소를 제거함.
stream1.distinct().forEach(e -> System.out.print(e + " "));
stream2.filter(n -> n % 2 != 0).forEach(e -> System.out.print(e + " "));
//홀수만
- 스트림 변환
- map() : 반환값들로 이루워진 스트림
Stream<String> stream =Stream.of("Hello", "HI", "Bye", "good");
stream.map(s->s.length()).forEach(system.out::println);
- flatMap() : 스트림들을 하나의 스트림으로 합쳐서 하나의 새로운 스트림
String[] arr = {"I study hard", "You study JAVA", "I am hungry"};
Stream<String> stream = Arrays.stream(arr);
stream.flatMap(s -> Stream.of(s.split(" "))).forEach(System.out::println);
=> 단어별 출력
- 스트림 제한
- skip() : 해당 변수를 첫번째 요소로 지정함.
- limit(개수) : 개수만큼 출력
IntStream stream1 = IntStream.range(0,10);
IntStream stream2 = IntStream.range(0,10);
IntStream stream3 = IntStream.range(0,10);
stream1.skip(4).forEach(n -> System.out.print(n + " "));//4 5 6 7 8 9
stream2.limit(5).forEach(n -> System.out.print(n + " "));//0 1 2 3 4
stream3.skip(3).limit(5).forEach(n -> System.out.print(n + " "));// 3 4 5 6 7
- 스트림 정렬
정렬은 배열과 동일 sorted();
-
역 정렬시
stream.sorted(Camparator.reverseOrder())
- 스트림 연산 결과 확인
peek()
- foreach 는 스트림을 소비해서 다음 연산이 불가능하고 peek 는 스트림을 소비하지 않아서 다음 연산이 가능함
Stream.of("one", "two", "three", "four")
.filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());
Filtered value: three Mapped value: THREE Filtered value: four Mapped value: FOUR
스트림 최종 연산
-
요소의 출력 : forEach()
-
요소의 소모 : reduce()
List<Integer> ages = new ArrayList<Integer>();
ages.add(1);ages.add(2);ages.add(3);//1,2,3
System.out.println(ages.stream().reduce((b,c) -> b+c).get());//1+2+3=6
-
요소의 검색 : findFirst(), findAny()
-
요소의 검사 : anyMatch(), allMatch(), noneMatch()
-
anyMatch() : 해당 스트림의 일부 요소가 특정 조건을 만족할 경우에 true를 반환함.
-
allMatch() : 해당 스트림의 모든 요소가 특정 조건을 만족할 경우에 true를 반환함.
-
noneMatch() : 해당 스트림의 모든 요소가 특정 조건을 만족하지 않을 경우에 true를 반환함.
-
-
요소의 통계 : count(), min(), max()
IntStream stream = IntStream.of(30,90,70,10);
System.out.pritnln(stream.count());
-
요소의 연산 : sum(), average()
-
요소의 수집 : collect()
참고자료
예제
https://www.baeldung.com/java-streams-peek-api
https://jeong-pro.tistory.com/165
추가설명
Comments