// 기존의 Java 7방식의 작성 방법
List<String> list = Arrays.asList("fast","campus","rocks");
List<String> newList = new ArrayList<>();
for (String s : list){
newList.add(s.toUpperCase());
}
for (String s : newList){
System.out.println(s);
}
// java 8 - Stream API -> 훨씬 더 간결한 코드로 작성할 수 있다.
List<String> list1 = Arrays.asList("fast","campus","rocks");
Stream<String> stream = list1.stream(); //스트림으로 변환해준다.
// 스트링에서 스트림으로 매핑해준다.
//uppercase를 string에 매핑, 각각의 요소에 적용해라
stream.map(String::toUpperCase).forEach(System.out::println); // foreach는 Consumer를 받는다,각각의 요소를 하나씩 출력한다.
외부 반복자 - 개발자가 코드로 직접 컬렉션 요소를 반복해서 요청하고 가져오는 코드패턴
(Iterator를 생각하면 될 것 같다. Iterator을 사용해서 반복문을 구현해서 하나씩 값을 출력하게
코드를 구현해야 하는 것을 말하는 것 같다.)
내부 반복자 - 컬렉션 내부에서 요소들을 반복시키고 개발자는 요소당 처리해야할 코드만 제공하는 코드 패턴
(forEach메소드 처럼 내부가 어떻게 구현되어있는지 모르지만 이것을 사용하면 요소들 하나씩 가져오라는 코드가 없지만
알아서 반복해서 반환시켜 처리해준다. 이런 것을 의미하는 것 같다)
내부 반복자의 이점 - 개발자는 요소 처리 코드에만 집중, 멀티 코어 cpu를 활용하기 위해 요소들을 분배시켜 병렬 처리 작업을 수 있다.
종류 | 처리 대상 |
---|---|
Stream<T> | 일반적인 객체를 처리 |
IntStream | 기본 자료형 int 를 처리 |
LongStream | 기본 자료형 long 을 처리 |
DoubleStream | 기본 자료형 double 을 처리 |
데이터 소스 | 메소드 |
---|---|
Collection | default Stream stream() |
Collection | default Stream parallelStream() |
Arrays | public static Stream stream(T[] array) |
Arrays | public static Stream of(T ... values) |
Arrays | public static IntStream stream(int[] array) |
Arrays | public static IntStream of(int ... values) |
Arrays | public static LongStream stream(long[] array) |
Arrays | public static LongStream of(long ... values) |
Arrays | public static DoubleStream stream(double[] array) |
Arrays | public static DoubleStream of(double ... values) |
구분 | 메소드 |
---|---|
int형 범위 | public static IntStream range(int startInclusive, int endExclusive) |
int형 범위 | public static IntStream rangeClosed(int startInclusive, int endInclusive) |
long형 범위 | public static LongStream range(long startInclusive, long endExclusive) |
long형 범위 | public static LongStream rangeClosed(long startInclusive, long endInclusive) |
Random p형 값 | public PStream ps() |
Random p형 값 | public PStream ps(long streamSize) |
Random p형 값 | public PStream ps(long streamSize, p origin, p bound) |
Stream<String> stream1 = list1.stream();
// 함수형 인터페이스랑 비슷함 P Type
// LongStream, DoubleStream 도 있다.
int[] ints = {4, 6, 2, 19, 2, 58, 4, 6, 5};
IntStream intStream = Arrays.stream(ints);
intStream.forEach(System.out::println);
Stream<Integer>
로 할 경우, Primitive Type
이 들어올 때 오토박싱으로 변경되고 다시 출력할 때 언방식이 되는데 이럴 때 오버헤드가 발생한다.IntStream
을 사용 할 경우, 오버헤드 필요 없이, WrapperClass
없이 사용 가능하다. 그래서 효율적이다.of()
를 이용해서 Collection
을 걸치지 않고도 스트림을 생성 가능DoubleStream doubleStream = DoubleStream.of(0.4, 0.6, 0.2, 1.2, 0.94);
doubleStream.forEach(System.out::println);
IntStream intStream1 = IntStream.range(0,10); // 0~9까지 10은 포함되지 않는다.
intStream1.forEach(System.out::println);
IntStream intStream2 = IntStream.rangeClosed(0,10); // 0~10까지 10포함된다.
intStream2.forEach(System.out::println);
// LongStream도 range, rangeClosed 가 있다.
Random random = new Random();
// LongStream longStream = random.longs();
// longStream.forEach(System.out::println); // 개수 제한 없이 무한히 출력
// 개수 제한 가능
LongStream longStream1 = random.longs(100);
longStream1.forEach(System.out::println); // 개수를 정해질 수있다 100개
// 개수제한 + 범위 제한 가능 젤 많이 사용함
LongStream longStream2 = random.longs(100,0,1000);
longStream2.forEach(System.out::println); // 개수를 정해질 수있다 0~1000까지 100개를 출력
stream() 대신 parallelStream()으로 변경
stream 생성 후 parallel()으로 병렬화
combiner를 이용해 병렬 스트림으로 생성된 컬렉션을 결합
인터페이스 | 리턴타입 | 메소드(매개변수) |
---|---|---|
java.util.Collection | Stream | parallelStream() |
java.util.Stream | Stream | parallel() |
java.util.Intstream | IntStream | |
java.util.Longstream | Longstream | |
java.util.Doublestream | Doublestream |
Stream<String> parStream = Arrays.stream(arr).parallel(); // 스트림을 parallel로 바꿔줌
System.out.println(parStream.map(String::length).count());
// parallelStream을 사용하면 연산 순서가 달라질 수 있다.
List<String> list4 = List.of("atwe","bff","cqqqw","dtwer");
Stream<String> stream6 = list4.parallelStream(); // 어떤 요소가 먼저 수행되는지 알 수 없음
// Stream<String> stream6 = list4.stream();
stream6.map(String::length).peek(s->System.out.println("A: "+ s))
.filter(value->value >=3)
.peek(s-> System.out.println("B :"+ s))
.forEach(System.out::println);
포크조인 프레임워크 동작 방식
포크 단계
조인 단계
실제로 병렬 처리 스트림은 포크 단게에서 차례대로 요소를 4등분 하지 않는다.
내부적으로 서브 요소를 나누는 알고리즘이 있기 때문에 개발자는 신경 쓸 필요가 없다.
포크조인풀(포크조인프레임워크는 내부적으로 스레드를 포크조인풀에서 관리한다.)
병렬 처리는 항상 빠르다?
병렬 처리에 영향을 미치는 3가지 요인
요소의 수와 요소당 처리 시간 - 요소우의 수가 적고 요소당 처리시간이 짧으면 순차 처리가 오히려 병렬처리보다
빠를 수 있다 병렬처리는 스레드풀 생성, 스레드 생성이라는 추가적인 비용이 발생하기 때문이다.
스트림 소스의 종류
코어의 수
*싱글코어 cpu일 경우 순차처리가 빠르다. 코어의 수가 많으면 병렬처리 속도가 빨라진다.
자바에서 스레드가 기본적인건 모르겠으나 여기서 7개의 스레드가 각각있다고 가정하고 동시에 동작을한다
스레드는 프로그램을 동작할 때 한줄씩 실행되는데 이 한 줄씩 실행되는 것이 여러개 있는 것이다.각각 독립적으로 한줄을 실행한다.
한줄 한줄 계산하는게 동시에 계산해도 된다 각각을 순수함수로 되어있어야 하니깐
[0,0,0,0,0,0]
[0,0,0,0,0,0]
[0,0,0,0,0,0]
[0,0,0,0,0,0]
명령형/ 순차처리 <-> 함수형/병렬처리 큰 간극을 보인다