스트림 사용 3단계
- 스트림 생성
배열이나 컬렉션의 요소들을 처리하려면 가장 먼저 요소들을 갖는 스트림을 생성해야 한다. - 중개 연산
중개 연산은 스트림을 받아서 스트림을 반환한다 데이터를 추출, 변환, 조합하는 작업 등을 수행 할 수 있고 여러개의 중개연산은 지정할 수 있다. - 최종 연산
결과를 산출하기 위한 최종 연산을 수행한다. 이떄 중개 연산에서 미뤘던 지연연산을 수행한다. 최종연산 이후로 스트림은 자동소멸하여 더는 사용할 수 없다.
스트림 특징
명령행 프로그래밍 방식
int[] num = {1,2,3,4,5};
int sum= 0;
for(int i=0;i<num.length;i++){
if((num[i]%2) ==1)
sum += num[i];
}
스트림 방식
int sum = Arrays.stream(num).filter((n)->n%2==1).sum();
- 파이프 필터 패턴
입력 : Arrays.stream(num)
필터링 : filter(람다식)
출력 : sum()
이처럼 스트링을 이용하여 각종 중개 연산을 수행한 다음 최종 연산을 수행해 결과괎을 산출하는 방식을 파이프 필터 패턴이라고 한다. - 지연연산
이전 명령문에서 fitler() 메서드의 람다식은 sum() 메서드가 실행되기 전에는 처리되지 않고 있다가 sum() 메서드가 실행될 때 처리한다. - 재사용 불가
스트림 방식으로 데이터를 처리한 다음 스트림이 자동으로 소멸하므로 재사용 할 수는 없다.
스트림 종류
BseStream : 모든 스트림 API의 상위 객체로서 가장 기본 스트림
Stream <T> : T타입의 데이터를 처리하기 위한 스트림
DoubleStream : 더블 타입 데이터 처리하기 위한 스트림
IntStream : 인트 타입
LongStream : 롱 타입
스트림 생성방법
컬렉션
java.util.Collection의 stream() 메서드 사용
List<Integer> myList = new ArrayList<>(); myList.add(20); myList.add(10); Stream<Integer> myStream = myList.stream();
배열
java.util.Arrays의 stream() 메서드사용
int[] arr = {10,20}; IntStream myStream = Arrays.stream(arr);
스트림 인터페이스
- <R, A> R collect(Collector<? super T, A, R> collector)
스트림 요소들을 기반으로 새로운 컬렉션 생성 - long count()
스트림 요소들의 개수를 반환 - void forEach(Consumer<? suepr T> action)
스트림의 모든 요소에 대한 반복문을 실행 - Strea filter(Predicate<? super T> predicate)
스트림 요소들을 기반으로 조건에 만족하는 요소만 선택하여 새로운 스트림 생성 - Strema map(Function<? super T,? extends R> mapper)
스트림 요소들을 조건에 지정된 값으로 변환하여 새로운 스트림 생성
ArrayList<Integer> myList = new ArrayList<>();
myList.add(20);
myList.add(10);
Stream<Integer> myStream = myList.stream(); //List -> Stream
myStream.forEach((n)->System.out.print(n+" ")); //스트림의 모든 요소에 람다식 실행
Optional<Integer> minVal = myList.stream().min(Integer::compare);
요소값을 비교하며 가장 작은 값을 반환한다. 비교는 java.lang.Integer 의 compare() 메서드가 수행하는데, 이때 메서드 참조 방식을 이용하여 Integer::compare로 표현한다. 람다식은 실행할 내용을 새로 구현하는 것이고, 메서드 참조는 기존에 구현된 내용을 재사용하는 방식이다.
Optional 클래스
스트림 연산의 최종값을가지는 컨테이너 성격의 객체이며, 최종값을 처리하는 각종 메서드가 선언되어 있다.
병렬 스트림
- 병렬 처리란?
스트림에서 데이터를 처리하는 방식은 순차처리와 병렬처리로 두 가지다. 예를 들어 요소들의 합을 구할 때 순차 처리는 요소들을 하나씩 읽어서 처리하는 방식이다. 병럴처리는 머지소트처럼 부분적으로 처리한 후 그 결과를 결합해서 최종 결괏괎을 구하는 방식이다. 병렬처리가 성능이 좋지만 구현하기 복잡하고 오류가 발상핼 수 있는 확률이 높아서 자바 API에서 제공하는 메서드를 사용하는 것이 좋다. - 병렬 스트림생성
Collection의 parallelStream(), Stream의 apralle() 메서드 이용
IntStream is = IntStream.rangedClosed(1,10000000);
long start = System.currentTimeMills();
int total = is.sum();
long end = System.currentTimeMills();
System.outprintln("순차처리:" + (end - start));
IntStream is2 = Instream.rangedClosed(1,1000000).parallel();
long start = System.currentTimeMills();
int total = is.sum();
long end = System.currentTimeMills();
System.outprintln("병렬처리:" + (end - start));
스트림 활용
- 매핑 작업
Contact.java public class Concat{ name, phoneNum; } Member.java public class Member{ name, phoneNum,region }
public class Test{ public static void main(String[] args){ List<Member> members = new ArrayList<>(); members.add(new Member("홍길동","123","서울)); members.add(new Member("후길동","213","대전)); members.add(new Member("갈길동","312","부산)); // 멤버 -> Contact Stream<Contact> contactList = members.stream().map((m)->new Contact(m.getName, m.getPhoneNum)); contactList.forEach(System.out::println); } }
mapToXXX()
매핑된 결과값을 객체 타입이 아닌 기본 타입의 데이터로 처리하고자 할 때는 Double, Long, Int 메서드를 사용해 기본 타입 스트림으로 반환받아 사용한다.
public class Test{
publics static void main(String[] args){
List<Double> list = new ArrayList<>();
list.add(1.1);
list.add(2.1);
list.add(3.1);
int[] arr = list.stream().mapToInt(Integer::intValue).toArray);
// 계산 1
Optional<Integer> sumValue = list.stream.().map((n)->(int)Math.ceil(n)).reduce((a+b)->a+b);
// 계산 2
int sum = list.stream().mapToInt((n)->(int)Math.ceil(n)).sum();// 버림 후 합구하기
}
}
Collection과 같이 Iterator를 제공하고 병렬처리 작업을 위해 Spliterator도 지원한다.