본문 바로가기

일/JAVA

java16.stream.pipeline

/*

스트림 파이프라인?

대량의 데이터를 가공해서 축소하는 것을 일반적으로 리덕션(Reduction)이라고 하는데, 데이터의 합계,

평균, 카운팅, 최대/최소값 등이 대표적인 reduction의 결과이다. 그러나 컬렉션의 요소를 리덕션의

결과물로 바로 집계할 수 없을 경우에는 집계하기 편리하도록 필터링, 매핑, 그룹핑등의 중간처리를 할

것이 필요하다.

 

1. 중간처리와 최종처리

스트림은 데이터의 필터링, 매핑, 정렬, 그룹핑등의 중간처리와 합계, 평균 등의 최종처리를 파이프

라인(Pipe Line)으로 해결한다. 파이프라인은 여러개의 스트림이 연결되어 있는 구조를 말한다.

 

중간스트림이 생성될 때 요소들이 바로 중간처리 되는 것이 아니라 최종처리가 시작되기 전까지는

중간처리가 지연(lazy)된다. 최종처리가 시작되면 비로소 컬렉션의 요소가 중간 스트림에서 처리되고

최종처리까지 처리하게 된다.

 

2. 중간처리와 최종처리 메서드

 

1) 중간처리 메서드

a. 필터링 : distinct(), filter()

b. 매핑 : flatMap(), flatMapDouble(),flatMapToLong(), flatMaptoInt(), map(), mapToDouble(), mapToLong, mapToInt(), asDoubleStream(), asLongStream(),boxed()

c. 정렬 : sorted()

d. 루핑 : peek()

 

2) 최종처리메서드

a. 매칭 : allMatch(), anyMatch(), nonMatch()

b. 집계 : count(), findFirst(), max(), min(), average(), sum(), reduce()

c. 루핑 : forEach()

d. 수집 : collect()

3.

 

*/

public class PipeLineMain {

 

public static void main(String[] args) {

 

List<Member> members = Arrays.asList(

new Member("홍길동", Member.MALE, 30),

new Member("홍길순", Member.FEMALE, 34),

new Member("홍길녀", Member.FEMALE, 32),

new Member("홍길상", Member.MALE, 28),

new Member("홍길성", Member.MALE, 35)

);

// 남자회원의 평균나이는?

// 1. 일반로직

double sum = 0.0;

for(Member member:members) {

if(member.getGender()==Member.MALE) {

sum+=member.getAge();

}

}System.out.println("남자회원의 평균나이= " +(sum/(members.size()-2)));

System.out.println();

 

// 2. stream로직(pipeline)

OptionalDouble avgAge = members.stream()

.filter(m->m.getGender()==Member.MALE) // 남자회원만 stream으로 다음으로 전달

.mapToInt(Member::getAge) // Member객체 '홍길동, 30' -> stream(30)만 다음으로 전달

.average(); //stream[30,28,35] -> 평균(OptionalDouble)

System.out.println("남자회원의 평균나이= "+avgAge.getAsDouble());

System.out.println();

 

double avg = members.stream()

.filter(m->m.getGender()==Member.FEMALE)

.mapToInt(Member::getAge)

.average()

.getAsDouble();

System.out.println("여자회원의 평균나이= "+avg);

}

}

 

class Member{

public static final int MALE = 0;

public static final int FEMALE = 0;

private String name;

private int gender;

private int age;

 

public Member(String name, int gender, int age) {

this.name = name;

this.gender = gender;

this.age = age;

}

public String getName() {

return name;

}

public int getGender() {

return gender;

}

public int getAge() {

return age;

}

}

public class FilteringMain {

 

public static void main(String[] args) {

 

List<String> names = Arrays.asList("홍길동","소향","손흥민","소향","홍길녀");

// 1. distinct() // 중복제거 후...

names.stream().distinct().forEach(System.out::print);

System.out.println();

// 2. filter() : "소"로 시작하는 이름만 필터

names.stream().filter(n->n.startsWith("소")).forEach(System.out::println);

System.out.println();

// 3. 중복제거후, 소향만 출력

names.stream().distinct().filter(n->n.startsWith("소")).forEach(System.out::print);

System.out.println();

names.stream().filter(n->n.startsWith("소")).distinct().forEach(System.out::print);

System.out.println();

 

}

 

}

public class AsStreamMain {

 

public static void main(String[] args) {

 

int[] int_array= {1,2,3,4,5};

// 1. asDoubleStream : int, long타입의 값을 double로 변환

IntStream int_stream = Arrays.stream(int_array);

int_stream.asDoubleStream().forEach(System.out::println);

System.out.println();

 

// 2. boxed() : int -> Integer, long -> Long, double -> Double로 박싱 후 리턴

int_stream = Arrays.stream(int_array);

int_stream.boxed().forEach(obj->System.out.println(obj.intValue()));

System.out.println();

 

int_stream = Arrays.stream(int_array);

int_stream.boxed().forEach(obj->System.out.println(obj.getClass()));

}

 

}

/*

매핑(flatMapXXX(),mapXXX, asXXXStream(), boxed())

매핑은 중간처리기능으로 스트림의 요소를 다른 요소로 대체하는 작업을 말한다. 스트림에서

제공하는 매핑메서드는 flatMapXXX(), mapXXX, asXXXStream(), boxed()가 있다.

 

1. flatMapXXX() : 이 메서드는 요소를 대체하는 복수개의 요소들로 구성된 새로운 스트림으로 리턴

2. mapXXX : 이 메서드는 요소를 대체하는 요소로 구성된 새로운 스트림으로 리턴

3. asXXXStream()

a. asDoubleStream()메서드는 IntStream의 int, LongStream의 long의 값들을 double타입으로 리턴

b. asLongStream()메서드는 IntStream의 int값을 long으로 타입변환후 LongStream으로 리턴

4. boxed() : int, long, double 기본타입을 각각 Integer, Long, Double로 박싱을 해서 stream으로 리턴

*/

public class FlatMapMain {

 

public static void main(String[] args) {

// 1. flatMap : 복수 개의 요소로 대체

List<String> list1 = Arrays.asList("java8 lambda", "stream mapping");

list1.stream().flatMap(data -> Arrays.stream(data.split(" "))) // java8, lambda, stream, mapping

.forEach(System.out::println);

System.out.println();

// 2. flatMapToInt

List<String> list2 = Arrays.asList("10,20,30","40,50,60,70,80,90,100");

list2.stream().flatMap(data -> Arrays.stream(data.split(","))) // 10~100

.forEach(System.out::println);

System.out.println();

 

// data -> {} 처리

list2.stream().flatMapToInt(data->{

String[] str_arr = data.split(",");

int[] int_arr = new int[str_arr.length];

for(int i=0;i<str_arr.length;i++) {

int_arr[i] = Integer.parseInt(str_arr[i].trim());

}

return Arrays.stream(int_arr);

}).forEach(System.out::println);

}

 

}

public class MapMain {

 

public static void main(String[] args) {

// 1. map : 특정의 요소를 전달 받아서 다른 형태의 stream으로 리턴

List<Student> list = Arrays.asList(

new Student("홍길순",90),

new Student("홍길동",80),

new Student("홍길자",85)

);

list.stream().mapToInt(Student::getScore).forEach(System.out::println);

int sum = list.stream().mapToInt(Student::getScore).sum();

System.out.println("학생들의 총점= "+sum);

}

 

}

 

class Student{

private String name;

private int score;

public Student(String name, int score) {

this.name = name;

this.score = score;

}

public String getName() {

return name;

}

public int getScore() {

return score;

}

 

}

public class SortMain {

 

public static void main(String[] args) {

// 1. 기본타입정렬

IntStream stream = Arrays.stream(new int[] {5,3,4,1,2});

stream.forEach(System.out::println);

System.out.println();

 

stream = Arrays.stream(new int[] {5,3,4,1,2});

stream.sorted().forEach(System.out::println);

System.out.println();

 

 

// 2. 참조타입정렬(Member의 name)

List<Member> members = Arrays.asList(

new Member(3, "홍길동"),

new Member(1, "홍길순"),

new Member(2, "홍길녀")

);

members.stream().forEach(m->System.out.println(m.toString()));

System.out.println();

members.stream().forEach(m->System.out.println(m));

System.out.println();

members.stream().forEach(System.out::println);

System.out.println("==================================================");

 

//sorted 오름차순

members.stream().sorted().forEach(System.out::println);

System.out.println();

 

//sorted 내림차순

members.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);

 

 

}

}

 

class Member implements Comparable<Member>{

public int no;

public String name;

public Member(int no, String name) {

super();

this.no = no;

this.name = name;

}

public int getNo() {

return no;

}

public String getName() {

return name;

}

 

@Override

public String toString() {

return "Member[no="+no+", name="+name+"]";

}

@Override

public int compareTo(Member m) {

// return Integer.compare(this.no, m.no); // 번호순정렬

return this.name.compareToIgnoreCase(m.name);

 

 

}

}

 

/*

루핑(중간처리 peek(), 최종처리 forEach())

루핑(Looping)은 요소 전체를 반복하는 것이다. 루핑메서드는 peek()와 forEach()가 있는데

이 두 메서드는 반복처리하는 기능은 동일하지만 peek()는 중간처리 메서드이고 forEach()는

최종처리 메서드이다.

 

peek()는 중간처리단계에서 전체요소를 루핑하면서 추가적인 작업을 하기 위해 사용되며 최종

처리 메서드가 실행되지 않으면 지연(lazy, 처리가 되지 않는다는 의미)이 되기 때문에 반드시

최종처리메서드가 호출되어야만 동작한다.

 

요소처리의 최종단계가 합계를 구하는 것이라면 peek()호출 후 sum()을 호출해야만 peek()가

정상적으로 동작한다.

 

하지만, forEach()는 최종처리 메서드이기 때문에 파이프라인 마지막에서 루핑하면서 요소를

하나씩 처리한다. forEach()는 최종처리이기 때문에 다른 최종처리인 sum()과 같은 최종처리

메서드를 호출하면 에러가 발생한다.

*/

public class LoopingMain {

 

public static void main(String[] args) {

int[] int_array = {1,2,3,4,5,6,7,8,9,10};

 

//실습. 짝수의 합계를 stream으로처리하기

//filter().sum()

int sum = Arrays.stream(int_array)

.filter(n->n%2==0)

.sum();

System.out.println("1~10까지 합= "+sum);

System.out.println();

 

System.out.println("[1.peek()를 마지막에 호출하는 경우]");

Arrays.stream(int_array)

.filter(n->n%2==0)

.peek(n->System.out.println(n+","));

System.out.println();

 

 

System.out.println("[2.최종처리를 마지막에 호출하는 경우]");

sum = Arrays.stream(int_array)

.filter(n->n%2==0)

.peek(n->System.out.print(n+","))

.sum();// 중간처리이기 때문에 sum()최종처리가 호출되었기 때문에 실행

System.out.println("\n1~10까지 합= "+sum);

System.out.println();

 

 

System.out.println("[3.forEach()를 마지막에 호출하는 경우]");

Arrays.stream(int_array)

.filter(n->n%2==0)

.forEach(n->System.out.print(n+","));

}

 

}

/*

매칭(allMatch(), anyMatch(), nonMatch())

스트림클래스는 최종처리단계에서 요소들이 특정조건에 맞는지 여부를 조사할 수 있도록

세가지 매칭메서드를 제공하고 있다.

 

1. allMatch() : 모든 요소들이 매개값으로 주어진 조건에 만족하는지 여부를 리턴

2. anyMatch() : 최소한 한 개의 요소가 주어진 조건에 만족여부를 리턴

3. nonMatch() : 모든 요소들이 만족하는지 여부를 리턴

*/

public class MatchMain {

 

public static void main(String[] args) {

 

int[] int_arr = {2,4,6};

 

// 1. allMatch()

boolean result = Arrays.stream(int_arr).allMatch(n->n%2==0);

System.out.println("스트림요소 전체가 2의 배수인가 "+result);

System.out.println();

// 2. anyMatch()

result = Arrays.stream(int_arr).anyMatch(n->n%3==0);

System.out.println("스트림요소 하나라도 3의 배수인가 "+result);

System.out.println();

// 3. noneMatch()

result = Arrays.stream(int_arr).noneMatch(n->n%3==0);

System.out.println("스트림요소 하나라도 3의 배수가 없나 "+result);

System.out.println();

 

}

 

}

 

' > JAVA' 카테고리의 다른 글

java16.stream.aggregate  (0) 2023.05.30
java16.stream.intro  (0) 2023.05.30
java15.collection  (0) 2023.05.26
java14.lambda 람다람다  (0) 2023.05.26
java13.generic  (1) 2023.05.26