병렬처리
- 프로그램 내에서 영역을 여러 개로 나누어 각각의 계산을 여러 프로세스에서 동시에 수행하는 것이다.
- 자바에서는 병렬처리를 Stream API를 통해 집계 또는 연산을 할 수 있도록 제공하며 손쉽게 구현할 수 있도록 클래스와 메소드를 제공한다.
- 자바에서의 Stream API는 주로 배열이나 Collection 등의 집합체를 바탕으로 값의 집계나 데이터를 사용한 처리 API이다.
Stream API
- 스트림의 구조는 크게 3가지로 나뉜다.
- 스트림 생성
- 중개 연산
- 최종 연산
- [예시]
Collection집합.스트림생성().중개연산().최종연산(); - 계속해서 .으로 연계할 수 있게 하는 방법을 파이프라인이라고 한다.
- Stream은 재사용이 불가능하다.
- 병렬 스트림인 parallelStream의 경우 여러 쓰레드가 작업한다.
Stream 생성
- java.util.stream.Stream의 of()
- java.util.Array의 stream()
- java.util.Collection의 stream()
- 위 세 가지의 메소드를 통해 만들 수 있으며, 대상 객체를 Stream으로 반환하게 되면 Map, Reduce등의 집계를 간편하게 구현할 수 있다.
public class Test {
public static void main(String[] args) {
List<String> list =Arrays.asList("사원1","사원2","사원3","사원4");
String [] array = {"관리자1","관리자2","관리자3","관리자4"};
//1. 리스트를 스트림으로 변환(병렬 작업 위해서)
Stream<String> stream1=list.stream();
//2. 배열을 스트림으로 변환
Stream<String> stream2=Arrays.stream(array);
//3. 문자열 여러개를 래퍼클래스로 변환을 해서 스트림으로 구현
Stream<String> stream3=Stream.of("1","2","3","4","5");
Stream<String> stream4=Stream.of(array);
//4. 출력
PrnStream(stream1);
PrnStream(stream2);
PrnStream(stream3);
PrnStream(stream4);
Stream<Integer> stream5=Stream.of(1,3,2,4,5,6);//래퍼 클래스로 변환하는 것이니
//Int를 Integer로 바뀐다.
PrnStream01(stream5);
}
private static void PrnStream01(Stream<Integer> my_stream) {
my_stream.forEach(e->System.out.printf("%5d",e));
System.out.println("\n===========================");
}
private static void PrnStream(Stream<String> my_stream) {
my_stream.forEach(e->System.out.printf("%5s",e));
System.out.println("\n===========================");
}
}
//출력
//사원1 사원2 사원3 사원4
//===========================
//관리자1 관리자2 관리자3 관리자4
//===========================
// 1 2 3 4 5
//===========================
//관리자1 관리자2 관리자3 관리자4
//===========================
// 1 3 2 4 5 6
//===========================
객체 출력
스트림 변환 후 검색, 집계, 연산 등을 구현한 다음 마지막에 출력할 때 사용한다.
- void forEach(Consumer <? super T> consumer)
- void forEachOrder(Consumer <? super T> consumer)
- Consumer는 값을 받아 처리하지만 반환 값을 리턴하지 않는 인터페이스이다.
Stream 내부 작업
1. map(중개 연산)
Stream 인스턴스의 각 요소를 조건에 맞춘 새로운 stream으로 검색하거나, 다른 데이터 요소를 가진 stream 인스턴스를 생성하는 작업을 한다.
- filter(Predicate<? super T> predicate)
- prediacte에 정의된 boolean 리턴 값이 true에 해당하는 요소만 Stream<T>로 변환
- limit(long maxSize)
- 요소의 처음부터 maxSize까지의 요소의 Stream을 리턴
- distinct()
- 요소끼리 equals 메소드에서 비교하여 중복 항목을 제외한 Stream으로 리턴
- map(Function<? super T, ? extends R> mapper)
- 지정된 값을 변경한 새로운 Stream을 Return
- 입력 T를 R로 변환하는 함수 인터페이스이며 Function을 매개인자로 갖는다.
- flapMap(Function <? super T, ? extends Stream<? extends R>> mapper)
- 입력된 T를 복수개의 R로 변환하는 map 메소드로 flatMap에서 만들어진 Stream은 자동으로 close된다.
- peek(Consumer<? super T> action)
- 변환하는 작업을 테스트할 때 사용하는 메소드이다.
- 디버깅 용도로 어떤 값이 들어 있는지 확인하고 싶을 때 사용한다.
- 요소의 수에 어떤 영향도 주지 않는다
public class MapTest {
public static void main(String[] args) {
Integer [] array = {1,2,3,4,5,1,2,3,4,5};
//메소드 참조 class_name::method_name=static
System.out.println(" 1. filter 메소드로 짝수만 출력해보자. ");
Arrays.stream(array).filter(value -> value%2==0)
.forEach(System.out::println);
//filter안에는 predicate 안에 들어 있는 test가 들어갔다.
System.out.println(" 2. limit 메소드로 3개의 요소만 출력해보자. ");
//메소드 참조 class_name::method_name=static
Arrays.stream(array).limit(3).forEach(value->System.out.println("value: "+value));
System.out.println(" 3. distinct 메소드로 중복되지 않는 요소만 출력해보자");
Arrays.stream(array).distinct().forEach(System.out::println);
System.out.println(" 4. map을 활용하여 대문자로 만들어 보자.");
Stream<String> stream= Stream.of("java","jsp","spring","jqeury");
stream.map(s->s.toUpperCase()).forEach(System.out::println);
//map은 값을 다른 값 또는 다른 메서드로 변환하는 메서드이다.
System.out.println(" 5. map() / peek() 을 사용하여 값을 체크해보자.");
Stream<String> stream01= Stream.of("루리","루세","루오","폴리");
stream01.peek(s->System.out.printf("체크한 결과: %s",s)).map(t-> "\t실제 값:"+t)
.forEach(System.out::println);;
//데이터를 복수 개 리턴
System.out.println(" 6. flatMap()을 사용하여 세번째 값에 있는 것을 이용하여 반복 출력하자.");
List<String> list= Arrays.asList("사과3팩","멜론2팩","딸기3팩","망고2팩");
//list에 있는 것을 하나씩 넣는다 list.stream
List<String> result=list.stream().flatMap(
s->{
String c=s.substring(0,2);
int num=Integer.parseInt(s.substring(2,3));
String [] array2= new String[num];
Arrays.fill(array2, c); //array 칸 모두를 c로 채운다.
return Stream.of(array2);//리턴 값은 스트림이다.}
}).collect(Collectors.toList());
//collect 이용하면 list나 Set 사료형 가능
System.out.println(result);
}
}
//결과
//1. filter 메소드로 짝수만 출력해보자.
//2
//4
//2
//4
//2. limit 메소드로 3개의 요소만 출력해보자.
//value: 1
//value: 2
//value: 3
//3. distinct 메소드로 중복되지 않는 요소만 출력해보자
//1
//2
//3
//4
//5
//4. map을 활용하여 대문자로 만들어 보자.
//JAVA
//JSP
//SPRING
//JQEURY
//5. map() / peek() 을 사용하여 값을 체크해보자.
//체크한 결과: 루리 실제 값:루리
//체크한 결과: 루세 실제 값:루세
//체크한 결과: 루오 실제 값:루오
//체크한 결과: 폴리 실제 값:폴리
//6. flatMap()을 사용하여 세번째 값에 있는 것을 이용하여 반복 출력하자.
//[사과, 사과, 사과, 멜론, 멜론, 딸기, 딸기, 딸기, 망고, 망고]
2. Reduce(최종 연산)
리턴 받은 stream 인스턴스의 요소에서 어떤 결과를 얻거나 요소를 사용하여 출력하는 등의 작업을 담당한다.
- get()
- Optional <T>에 들어 있는 값을 리턴한다.
- 포함하고 있는 값이 업는 경우 NoSuchElementException 예외가 발생한다.
- isPresent()
- 값이 포함되어 있는 경우 true, 포함되지 않는 경우 false를 리턴한다.
- orElse(T other)
- 값이 포함되어 있는 경우에는 그 값을 리턴하고, 저장되어 있지 않은 경우네는 인수 other에 저장한다.
- orElseGet(Supplier<? extends T> other)
- 값이 포함되어 있는 경우는 그 값을 리턴하고 포함되지 않는 경우 supplier가 생성한 값을 리턴한다.
- orElseThrow(Supplier<? extends X> exceptionSupplier)
- 값이 포함되어 있는 경우는 그 값을 반환하고 포함되지 않는 경우 supplier가 발생 시키는 예외를 생성한다.
- of(T value)
- ofNullable(T value)
- Optional의 static 메소드로 인수 value가 null이 아닌 경우,그 value를 포함하는 Optional을 리턴하고 null의 경우는 Optional의 empty 메소드로 생성되는 Optional을 리턴한다.
- empty()
- ifPresent(Consumer<? super T> consumer)
- Optional 값을 포함하고 있는 경우 consumer 작업을 수행하고
Optional이 Empty인 경우에는 아무것도 하지 않는다.
- Optional 값을 포함하고 있는 경우 consumer 작업을 수행하고
- reduce(BinaryOperator<T> accumulator)
- accumulator 처리 할 BinaryOperator결과와 요소을 사용하여 처리를 반복하고 처리 결과를 optional로 리턴한다. 만일 요소가 없는 등의 결과가 없는 경우는 empty 의 optional를 리턴한다.
- T reduce (T identifier,BinaryOperatorl <T>accumulator)
- 처음 설정 값으로 제 1 인수에 T를 설정하여 T를 첫 번째 값으로 BinaryOperator 처리를 반복하고, 그 결과를 T로 리턴, Stream에 요소가 없는 경우는 T의 identifier 값을 리턴 한다
- U reduce (U identifier,BinaryFunction <U? super T, U>accumulator, BinaryOperator <U>combiner)
- stream 가지는 형태와 결과로 반환하는 형식이 다른 경우에 사용하는 reduce 메소드.
제 1 인수를 첫 번째 값으로 U를 받고 BinaryFunction에서 Stream 요소 T를 받은 U를 사용하여 처리하고,
제 1 인수와 같은 U의 형태로 변환하여 결과를 리턴한다.
병렬 처리의 경우, 제 3 인수 BinaryOperator 분산된 BinaryFunction 결과 U를 받고 결과를
정리해 생성하는 처리를 한다. Stream에 요소가 없는 경우 제 1 인수의 값이 리턴된다.
- stream 가지는 형태와 결과로 반환하는 형식이 다른 경우에 사용하는 reduce 메소드.
package com.test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
//reduce accumulator 처리 할 BinaryOperator 결과와
//reduce 요소를 사용하여 처리를 반복하고 처리 결과를 optional로 리턴
//만일 요소 가 없는 등 결과가 없는 경우 empty의 optional로 리턴
public class ReduceTest {
public static void main(String[] args) {
//Optional<T> reduce(BinaryOperator<T> accumulator)
System.out.println("1. reduce를 이용해서 멤버의 합을 구해보자. ");
List<Integer> numbers=Arrays.asList(10,20,30,40,50);
Optional<Integer> sum= numbers.stream().reduce(Integer::sum);
if(sum.isPresent()) {
System.out.println(sum.get());// get Optional <T>에 있는 값 리턴
}else {
System.out.println("novalue");
}
// T reduce(T identity, BinaryOperator<T> accumlulator)
System.out.println("2. 매개인자 2개로 받아 T로 리턴하는 메소드를 활용");
List<Integer> numbers02=Arrays.asList(10,20,30,40,50);
//100+10+20+30+40+50
int sum01= numbers02.stream().reduce(100,Integer::sum);
System.out.println(sum01);
System.out.println("3. 매개인자 3개로 받아 U로 리턴하는 메소드를 활용");
List<Integer> numbers03=Arrays.asList(10,10,20,20,30,40,50);
double sum02=numbers03.parallelStream()
.reduce(0.0, (partialSum, a)
-> partialSum +a, Double::sum);
//세 개인 경우, 맨 앞은 초기 값,
System.out.println(sum02);
}
}
Java Collectors(Class) and Collector(Interface)
public class CollectorTest {
public static void main(String[] args) {
Stream<String> s =Stream.of("a","b","c");
Collection<String> res=s.collect(Collectors.toCollection(TreeSet::new));
System.out.println(res);
s =Stream.of("a","b","c","d","c");
res=s.collect(Collectors.toSet()); //셋이니 중복 데이터 제거 되어서 나온다.
System.out.println(res);
s =Stream.of("a","b","c","f","c");
res=s.collect(Collectors.toList());
System.out.println(res);
}
}
- collect()
- stream에서 수행한 작업 결과를 수집하고 싶을 때 사용
- 수집된 데이터가 Collector로 변환한다. (List, Set, Map 으로 상태 변경 가능)
- Collectors
- final 클래스로 모든 메소드가 static으로 되어 있고 리턴 값이 Colletor 인터페이스로 리턴되나.
- R collect(Collector collector)
- Collector 인터페이스에 의해 stream 요소를 사용하여 생성된 결과를 리턴.
java.util.stream.Collector의 메소드를 사용할 때 적합
- Collector 인터페이스에 의해 stream 요소를 사용하여 생성된 결과를 리턴.
- collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R,R> combiner):
- supplier 생성된 R에 스트림 요소에서 리턴 받은 값을 accumulator에서 R에 저장하고모든 요소의 처리가 끝날 때 R로 리턴한다.
Comparator를 사용한 Lamda
public class ComparatorTest {
public static void main(String[] args) {
List<String> str=Arrays.asList("딸기","바나나","수박","멜론");
Optional<String> o_min=str.stream().min(Comparator.naturalOrder());
Optional<String> o_max=str.stream().max(Comparator.naturalOrder());
Optional<String> find_one=str.stream().findFirst();
Prn(o_min);
Prn(o_max);
Prn(find_one);//첫번째 잡히는 데이터 find Any
}
private static void Prn(Optional<String> o) {
if(o.isPresent()) {
System.out.println(o.get());
}else
{
System.out.println("없음.");
}
}
}
//딸기
//수박
//딸기
'JAVA' 카테고리의 다른 글
Java Collectors의 메소드 정리(for 람다) (0) | 2021.09.19 |
---|---|
함수형 인터페이스(Functional Interface) & 기초 람다 (0) | 2021.09.17 |
JavaFX GUI활용한 프로그램 개발 (0) | 2021.08.12 |
JAVA 클래스와 객체 (0) | 2021.08.10 |
java와 javac 버전이 다를 때 해결법(Window) (0) | 2021.07.20 |