Java ch 14 스트림

Java ch 14 스트림

● ch 14-1~4 람다식이란? 람다식 작성하기

// Java는 원래 Oop 객체지향 언어인데 JDK 1.8부터 빅데이터 같은 엄청난 데이터를 처리하기 위해 함수형 언어가 추가되었다. 함수형 기능이 있는 언어를 포함했다는 소리. //14장에서 배운 게 파이썬과 JS를 공부하는데 큰 도움!!

· 람다식

- 함수(메서드)를 간단한 식으로 표현하는 방법

- 익명 함수(이름이 없는) 함수 (anonymous function)

// 반환타입과 함수 이름을 지우고 사이에 화살표를 넣는다. 그러면 람다식이 된다.

- 함수와 메서드의 차이

=> 근본적으로 동일. 함수는 일반적 용어, 메서드는 객체지향개념 용어

=> 함수는 클래스에 독립적, 메서드는 클래스에 종속적. 자바는 클래스 밖에 있을 수 없기에 전부 메서드이다!

· 람다식 작성하기

1. 메서드의 이름과 반환 타입을 제거하고 -> 을 구현부 {} 앞에 추가한다.

2. 반환값이 있는 경우, 식이나 값만 적고 return문 생략가능 (끝에 ; 안붙임)

3. 매개변수의 타입이 추론 가능하면 생략가능(대부분의 경우 생략 가능)

· 람다식 작성하기 – 주의사항

1. 매개변수가 하나인 경우, 괄호() 생략가능( 타입이 없을 때만)

// int a에서 int를 남겨놓기에 에러가 발생하므로 그냥 int를 없애려고 한다.

// () 는 그대로 남겨둔다.

2. 블록안의 문장이 하나뿐일 때, 괄호{} 생략가능 (끝에 ; 안 붙임)

// 단 하나뿐인 문장이 return 문이면 괄호{} 생략불가

· 람다식은 익명 함수? 익명 객체!

- 람다식은 익명 함수가 아니라 익명 객체이다.

# 익명객체: 객체의 선언과 생성을 동시에 한다. 원래는 오른쪽처럼 써야하는데, 람다식으로 왼쪽처럼 쓰는 것!

- 객체를 다루려면 참조변수가 필요한데, 람다식(익명객체)을 다루기 위한 참조변수의 타입은?

// max 라는 메서드를 가지고있어도 쓰질 못 한다. 새로운 Object 객체에는 max 메서드가 있는데. 기존의 Object 리모콘에는 max를 호출하는 버튼이 없기 때문에.... 그래서 형변환해줘야하는데, 해줄 게 없어서 이 때 필요한 것이 함수형 인터페이스다.

++ 자바에서는 하나의 람다식만으로 표현할 수 없기에 new object(){} 안에 들어가는, 익명 객체 안에 있는 메서드 로 작성해야한다.

● ch 14-5,6 함수형 인터페이스

· 함수형 인터페이스

- 단 하나의 추상메서드만 선언된 인터페이스 => 람다식을 다루기위해

// 함수형 인터페이스 위에 @funtionalInterface 라는 애너테이션을 붙이면 이 함수형 인터페이스를 올바르게 작성했는지 컴파일러가 확인해준다.

// 익명 클래스의 선언 객체생성 동시에 진행한다. 그리고 전에는 Object를 썼지만 이제는 함수형 인터페이스를 쓴다.

int value=obj.max(3,5) 객체를 object로 했을 때는 형변환도 할 수 없고 에러가 났지만, int value=f.max(3,5); // OK. MyFunction에 max() 가 있다.

- 함수형 인터페이스 타입의 참조변수로 람다식을 참조할 수 있음

(단, 함수형 인터페이스의 메서드와 람다식의 매개변수 개수와 반환 타입 이 일치해야함)

MyFunction f = (a,b) -> a>b ? a : b; int value= f.max(3,5); // 실제로는 람다식(익명 함수)이 호출됨 => 익명 객체를 람다식으로 대체

## 주의

1. 람다식(익명 객체)을 다루기 위한 참조변수의 타입은 함수형 인터페이스로 한다.

2. 추상메서드에있는 메서드이름과 연결되어있다.

3. 람다식은 단 하나의 메서드만 있기 때문에 함수형 인터페이스 쪽에만 이름을 붙이고, 추상메서드를 구현하는 람다 쪽에서는 이름을 안 써도 됨

정리하자면,

=> 함수형 인터페이스를 선언하고 거기에 람다식 메서드 이름을 붙여준다. 그리고나서, 함수형 인터페이스 참조변수에 람다식을 저장(익명 객체 대체). 이후, 람다식을 호출할 때, 참조변수.메서드이름 으로 호출하면 된다.

​· 함수형 인터페이스 example 예시

- 익명 객체를 람다식으로 대체

// Comparator c = (S1, S2) -> S2.compareTo(S1);​

​· 함수형 인터페이스를 이용하여 매개변수, 반환타입 사용

## 내가 크게 헷갈렸던 부분 !!!

- 함수형 인터페이스 타입의 매개변수

// 함수형 인터페이스로 메서드의 매개변수를 람다식으로 받을 수 있다. 아래 구문은 람다식을 매개변수로 받아서 해당하는 람다식.메서드를 호출(각 람다식의 같은 이름의 메서드 호출하는 구문) 람다식을 직접 매개변수로 주어도 된다.

- 함수형 인터페이스 타입의 반환타입

// 메서드의 반환타입으로 함수형 인터페이스를 활용하여 람다식을 반환할 수 있다. (잘 와닿지는...)

● ch14-7,8 java.util.function패키지

· java.util.function패키지

- 자주 사용되는 다양한 함수형 인터페이스를 제공한다. 개발자들 간에 표준화에 용이

// Consumer 반환하는 건 없고 받기만 한다. Supplier(공급만) 반대

// Function 가장 일반적인 함수 ,입력도 있고 출력도 있다. 를 넣으면 이 나온다.

// Predicate 는 조건식이다. 함수하고 똑같은데 차이는 입력받으면 그 결과를 true 아니면 false로 반환

ex) Predicate 를 쓰는법은 아래와같다

// 람다식인데 반환타입이 boolean 이어야 한다. 문자열을 받아서 문자열의 길이가 0 인지 확인하는 구문.

// 그리고 이 람다식을 어떻게 쓰냐면 test 에서 어떤 문자열을 준다. test가 뭐냐면 람다식에 붙인 메서드 이름이다.

// 이 람다식을 호출하려면 test 란 이름을 써야하는 것이다. 조건식을 포함하고 있기에 그냥 test만 호출하면 된다.

· 매개변수가 2개인 함수형 인터페이스 // 앞에 Bi가 붙는다(2개라는 뜻)

- 함수는 반환값이 0개 또는 1개여야 하는데 BiSupplier 는 2개를 줘야되니 여기에 없는 것이다.

// 함수 2개 까진있는데 3개는 없다. 입력을 3개를 받는 것을 쓰고싶으면 우리가 직접 만들면된다.

· 매개변수의 타입과 반환 타입이 일치하는 함수형 인터페이스

UnaryOperator 단항 연산자, Fuction은 T, R 둘 다 써줘야하는데, 얘는 T,T

BinaryOperator 이항 연산자

// identity() 는 항등함수로서 t를 넣으면 t가 나오는 것이다.

· 예제 Ex 14_2 매우 중요!!!

● ch14-9~12 Predicate의 결합. CF와 함수형 인터페이스

· predicate(조건식)의 결합 // predicate 여러 개를 하나로 결합할수 있다.

- and() ,or() ,negate()로 두 predicate 를 하나로 결합(default 메서드) //각각 &&, ||, ! 에 해당한다.

// 인터페이스의 메서드는 추상메서드인데 부가적으로 JDK1.8부터는 default 메서드와 static메서드가 추가되었음

​// p.negate() 는 i 가 100보다 크거나 같다로 변한다.

// and 와 or가 동시에 나올 때는 ()해주기!!

// 이제, all.test(숫자), all2.text(숫자)로 true/false 판별하면 된다!

- 등가비교를 위한 Predicate 의 작성에는 isEqual()를 사용(static메서드)

간단히쓰면 한줄로

- 두 줄의 function도 하나로 줄일 수 있다. 두 가지 방법이 있는데,

1. f.andThen(g) 라는걸 쓴다. 이는 f를 적용하고 그다음 g를 적용해라는 뜻이다.

// f 의 입력값은 String 이고 출력값은 Integer 이다.

=> 이 함수 2개를 연결하려면 f의 출력값과 g의 입력값이 같아야한다. String->Integer->String이 되는 과정이다.

2. f.compose(g) 는 g.andThen(f)와 똑같다. g를 앞에 세우고 그다음 f를 뒤에 세우는 것. 굳이 몰라도 된다.

​// 항등함수: 넣은 즉시 그대로 나오는 것을 뜻함.

· 컬렉션 프레임워크와 함수형 인터페이스

- 함수형 인터페이스를 사용하는 컬렉션 프레임워크의 메서드(와일드카드는 생략했다)

// 원래는 iterator를 써서 하나씩 읽어왔는데 람다식을 쓰면 한 줄로 해결가능.

● ch14-13,14 메서드 참조, 생성자의 메서드 참조

· 메서드 참조(method reference)

- 하나의 메서드만 호출하는 람다식은 메서드 참조로 간단히 할 수 있다. ​(람다식을 더 간단히 한 것이다.)

- 메서드참조란 클래스이름::메서드이름 쓰면 된다.

// 이렇게 쓸 수 있는 이유는 함수형 인터페이스에 정보가 다 있기 때문이다. ​Function<>에!

// 메서드참조가 3가지가 있다. static메서드참조와 인스턴스 메서드 참조를 주로 쓴다.

// 3번 특정 객체 인스턴스 참조는 잘 안 쓴다.

· static 메서드

// 위에 있는 식을 두 번째에 있는 람다식으로 바꾼다. 그런데, 어차피 입력받을 게 뭔지를 아니까 아래와 같은 메서드 참조로 바꾸는 것이다. 대신, 함수형 인터페이스를 참조변수로 계속 쓰되, 저리 표현할 수도 있는 것이다!

// 메서드 참조를 람다식으로 바꾸는 연습!! How? 먼저 입력이 무엇인지 보기. 모르면 책 보거나 api 문서 참고

· 생성자의 메서드 참조

- Supplier 는 공급해주는 애라서 입력이 없고 출력만 있다. MyClass 객체를 만들어서 준다.

이거를 짧게 쓰면 이렇다.

Supplier s =MyClass::new;

- 생성자의 매개변수가 있는 경우

// 객체 생성할 때 i 값을 줘야한다. ex) class MyClass {}에서 MyClass(int iv){this.iv = iv;} 같은 게 있는 경우

Function s = (i) -> new MyClass(i); //이러한 람다식을 더 간단히 참조하면 아래와 같다. Function s= MyClass::new; // 입력받는 걸 알고있으니까 뒤에 i 생략가능

· 배열과 메서드 참조

- 입력값은 배열의 길이가 된다. 입력이 있으니 Function이 되어야한다.

람다식에서 입력이 뭔지 아니까 x 생략, 배열 타입 뭐 만들지도 아니까 배열의 길이만 써도 되지만, 너무 쓸게없으니까 int[]::new 로 해줬다.

● ch14-15,16 스트림, 스트림의 특징

· 스트림(Stream) JDK1.8 부터 나옴 ## 스트림mf 데이터의 연속적인 흐름이라고 생각하면 된다.

- 다양한 데이터 소스를 표준화된 방법으로 다루기 위한 것

# 데이터 소스: 컬렉션이나 배열같이 여러 데이터를 저장하고 있는 것들

// 표준화 방법: 지금까지는 컬렉션프레임워크를 이용해서 컬렉션을 다뤄왔는데 List,set,map 이런 다양한 컬렉션 프레임워크를 표준화해서 다룰려고 했는데 사실상 실패했다. List,set 그리고 map 의 성격이 다르기 때문에 사용방법이 달랐다. => 드디어 스트림이라는게 나와서 진정한 통일이 가능하게 되었다.

컬렉션 LIST,SET,MAP과 배열 같은 다양한 데이터 소스로부터 스트림을 만들수 있다. 만들고 나서부터는 모두 같은 방식으로 작업을 처리한다. 중간 작업은 여러 번 할수 있고 최종연산(결과)은 1번만 할 수 있다.

// 스트림 작업 ​과정: 1. 스트림 만들기 2. 중간 연산 3. 최종연산을 통해 결과 반환

아래는 스트림으로 변환 하는 방법이다. 스트림을 생성하는 방법

· 스트림

- 스프림이 제공하는 기능-중간 연산과 최종연산

1. 중간연산 - 연산결과가 스트림인 연산. 반복적으로 적용가능

2. 최종연산- 연산결과가 스트림이 아닌 연산. 단 한번만 적용 가능( 스트림의 요소를 소모)

· 스트림의 특징

- 스트림은 데이터 소스로부터 데이터를 읽기만할 뿐 변경하지 않는다. //작업 후에도 원본은 그대로이다.

- 스트림은 Iterator 처럼 일회용이다 (필요하면 다시 스트림을 생성해야 함)

// 최종연산 하고나면, 스트림이 닫혀서 호출 x

- 최종 연산 전 까지 중간 연산이 수행되지 않는다. - 지연된 연산

// 무한 되는 스트림에서 중복제거란 불가능하다. 그런데도 아래 코드가 가능한 이유는 지연된 연산이기 때문이다.

=> 즉, 바로 실행하는 것이 아니라 최종연산 때 실행할 것이기에!!!

- 스트림은 작업을 내부 반복으로 처리할 수 있다.

//forEach라는 최종연산으로 처리한다. // forEach로 바꿀 수 있는 이유가 저렇게 for문을 메서드 안으로 넣기에!

- 스트림의 작업을 병렬로 처리 - 병렬스트림 (멀티 쓰레드로)

// 기본적으로 싱글스트림인데 빅데이터는 멀티쓰레드로 하는게 유리하므로(큰 작업)

//병렬 작업을 원하면, 기본스트림에 parallel() 이란 메소드만 붙이면된다.

// 반대로 할떄는 .sequential() 을 쓰면 된다. 이후의 작업은 똑같다.

- 기본형 스트림(성능 개선용): IntStream, LongStream, DoubleStream

## 오토박싱(기본형을 참조형 타입으로 변환) <-> 언박싱(계산할 때는 다시 원 타입)

(1) 오토박싱&언박싱의 비효율이 제거됨(Stream 대신 IntStream 사용)

(2) 숫자와 관련된 유용한 메서드를 Stream보다 더 많이 제공

// 지네릭스 에서는 Stream<타입> 타입에 기본형을 쓸 수 없다. 쓸려면 자동적으로 오토박싱&언박싱이 되어야하는데 이렇게 된다 => Stream

// 근데 이렇게 변환하는 거조차 데이터가 많으면 은근히 시간이 걸림.

// 기본형->참조형, 참조형->기본형으로 변환하는 비효율 과정을 없애기위해 IntStream 등을 사용하는 것

// 장점으로는 IntStream 은 int 형인걸 알기 때문에 기본적으로 count(),sum(),average() 이런 메소드들이 제공된다

● ch14-17~22 스트림만들기

· 스트림 만들기 - 컬렉션

1. 스트림 생성 2. 중간연산(0~n번) 3. 최종연산

- Collection 인터페이스의 stream() 으로 컬렉션을 스트림으로 변환

Stream stream() // Collection 인터페이스의 메서드

// 최종연산을 한 뒤에는 또 출력하고 싶으면 한번 더 스트림을 만들어야한다. 최종연산은 1번까지밖에 사용 못하기에

· 스트림 만들기 - 배열

- 객체 배열로부터 스트림 생성하기

- 기본형 배열로 부터 스트림 생성하기

// 기본형 스트림은 sum,average,count를 쓸 수 있는데 객체형(Stream ) 스트림은 count 밖에 못 쓴다

// 기본형 배열(숫자가 있는)을 쓴다면 IntStream을 쓰는 게 좋다.

· 스트림 만들기 - 임의의 수 (난수)

- 난수를 요소로 갖는 스트림 생성하기

유한스트림 만드는법

// ints(),longs(),doubles() 는 무한스트림을 생성한다.

// ints(int begin, int end) 의 경우, begin부터 end 사이에 있는 난수를 얻는다. end포함x

· 스트림 만들기 - 특정 범위의 정수

- 특정 범위의 정수를 요소로 갖는 스트림 생성하기(IntStream, LongStream)

// rangeClosed 를 쓰면 끝이 포함된다

· 스트림 만들기 - 람다식 iterate(),generate()

- 람다식을 소스로 하는 스트림 생성하기

// 이 메서드에 람다식을 주면 람다식을 이용해서 계속 스트림을 만들어낸다.. 무한스트림이다.

// limit 로 짤라주어야함, 앞에 있는 인자는 초기값임.

- iterate()는 이전 요소를 seed 로 해서 다음 요소를 계산한다. => 각 요소가 종속적. 이전 값이 다음 값에 영향.

// 계속 반환값이 입력값이 되는 무한 스트림

- generate()는 seed를 사용하지 않는다. (각 요소가 독립적)

Stream randomStream = Stream.generate(Math::random); //계속 0~1 난수 출력

Stream oneStream = Stream.generate( () -> 1); //계속 1이 나온다.

// iterate 는 초기값을 가지고 이전값에 계속 관계가 이어지는데

// generate 는 초기값을 안쓰고 이전값하고 관계가 없다.

· 스트림 만들기 - 파일과 빈 스트림

- 파일을 소스로 하는 스트림 생성하기

// lines() 란 메서드를 쓰면 파일의 내용을 한 줄씩(라인 단위로) 읽고 스트림 요소로 만든다.

- 비어있는 스트림 생성하기

Stream emptyStream=Stream.empty(); //empty()는 빈 스트림을 생성해서 반환

long count = emptyStream.count(); // count 값은 0이 출력됨

● ch 14-23~25 스트림의 연산

· 스트림의 연산

- 스트림이 제공하는 기능 - 중간 연산과 최종 연산

· 스트림의 연산- 중간 연산

// peek는 중간에 작업이 잘 수행했는지 확인하는 역할

// map과 flatmap이 좀 어렵다.

· 스트림의 연산 - 최종 연산

- reduce()와 collect()가 핵심이다.

● ch 14-26~29 스트림의 중간연산 (1)

· 스트림 자르기 - skip(), limit()

// skip3은 3번 건너뛰고 5개만 출력

· 스트림의 요소 걸러내기 - filter(), distinct()

// 부분 신경쓰지 x

// filter 부분에서 위 아래 같은 식이다!

· 스트림 정렬하기 - sorted()

- 정렬할 때 필요한 것 1. 정렬대상 2. 정렬 기준

// 스트림 요소가 기본정렬을 가지고있지않으면 두 번쨰 줄을 써야한다.

// comparator 클래스에 기본적으로 naturalOrder() 라는 메서드가 있다. sorted() 와 같다.

// 복습: .compareTo는 인스턴스 메서드이기에 참조변수, 매개변수가 필요하기에 S1, S2

// 역순이어도 대문자가 계속 앞으로 나온다.

· Comparator 클래스에 comparing() 으로 정렬 기준을 제공

comparing(Function keyExtractor) comparing(Function keyExtractor, Comparator keyComparator)

// 첫 번째 부분: (Student s)->s,getBan( ) 정렬기준을 반별로!! Comparator타입으로 반환 후, sorted가 이를 쓴다.

// 추가 정렬 기준을 제공할 때는 thenComparing()을 사용 (정렬기준 여러개일 때)

// 계속 thenComparing 으로 계속 이어주면 됨

● ch 14-30~34 스트림의 중간연산(2)

· 스트림의 요소 변환하기 - map()

- map 이라는 메서드는 매개변수로 Function 을 받는다. //타입에 ? super 는 신경x

// map() 을 이용해서 이름을 가져와서 String 타입의 스트림을 만든다.

=> 처음엔 Stream 인데 Stream으로 변환을 하는게 map 의 역할이다.

// map 사용 3번: 먼저, 파일이름을 얻어서 String으로 바꿔주고, 파일 확장자만 뽑아내고, 모두 대문자로 변환

// substring(start) : start부터 끝까지 추출

· 스트림의 요소를 소비하지 않고 엿보기 -peek()

- forEach 하고 똑같다. 다만, 중간연산이라 스트림 소비x. 매개변수로 Consumer 를 받는다.

ex) 중간 중간에 작업이 잘되었는지 확인하는 용도 (디버깅) 로 쓴다. => 중간중간 sop

· 스트림의 스트림을 스트림으로 변환 -flatMap()

// 아래는 문자열 배열 스트림이다. map 으로 스트림을 받으면 스트림 안에 또 스트림이 생성된다..

// 그래서, 한 문자열 씩 받고싶으면 flatMap 을 써야한다. 여러 개의 문자 배열을 하나의 문자배열로 만든다.

- 실습

아래는 긴문자열인데 한 단어씩 중복없이 스트림으로 받고싶다. 이럴 때도 flatmap을 쓴다.

// " "+ 는 정규식이다. 원래 " " 은 하나의 공백을 기준으로 나누는 건데 " "+ 는 공백이 하나 이상일 수도 있으니!

● ch 14-35~39 Optional

· Optional

- T타입 객체의 래퍼클래스 - Optional //래퍼클래스는 Integer, Long 같은거...

public final class Optional { private final T value; // T타입의 참조변수 => 모든 종류의 객체 저장 가능(null도!) ----- }

// Optional 를 통해 간접적으로 null을 다룰 수 있다. why?

(1) null을 직접 다루는 것은 위험. NullpointException 에러가 발생할 수도

(2) null을 체크하려면 if문 필수인데, 코드가 지저분해진다.

Object result = getResult(); // 반환 값은 무조건 null 이거나 객체이다. result.tostring() // result가 null이면 NullpointException 에러 발생 그래서, if(result ! = null) { println(result.toString()); } // 이와 같은 if구문이 필요하다.

=> 이런 문제점들을 해결하기위해 나온 것이 Optional

// result에 null을 저장해서 직접 다루는 것이 아니라 Optional 객체에 null을 저장하는 것. 그래서 result에는 항상 null 이 아니라 Optional 객체의 주소값이 저장되는 것!!

// String도 null을 직접 다루지않고 String str = "";처럼 빈 문자열로 초기화하거나 new char[0]처럼 길이가 0인 char 배열로 초기화! (null을 간접적으로 다루기위해)

· Optional 객체 생성하기

- Optional 객체를 생성하는 다양한 방법

// Str [객체주소] -> value 가 아니라 Optval [객체주소] -> Optional 객체 [객체주소] -> value 이렇게 하면 optval은 절대 null이 될 수 없다! 한 단계 더 거치는 것이다.

// 아래는 iv일 때, 배열에 null을 직접 저장하는 대신 길이가 0인 배열을 만드는 것과 모양새가 비슷하다는 것이다.

## int [] arr = new int[0]; 도 비슷한 과정을 거치는 게 맞는지 그림으로 확인해보자!!

· Optional 객체의 값 가져오기

- Optional 객체의 값 가져오기 - get(), orElse(), orElseGet(), orElseThrow()

- isPresent() - Optional 객체의 값이 null이면 false, 아니면 true를 반환

// .orElse("")는 try-catch문을 짧게 줄인 것과 같다. 예외(null)이 발생하면,,, (삼항연산자와도 같다)

· OptionalInt, OptionalLong, OptionalDobule //성능을 높이기위해 사용. Optional 를 써도 되긴하나...

- 기본형 값을 감싸는 래퍼클래스

// 기본형 값인 경우, T 대신 해당 기본형 타입으로

// Int의 경우 아무 값도 저장하지않아도(빈 객체) 0인데, 이를 구분하기위해 boolean isPresent가 존재

● ch 14-40~44 스트림의 최종연산

· 스트림의 최종연산 - forEach(), forEachOrdered()

// 중간연산은 stream을 반환하고, 최종연산은 int, boolean, Optional 등을 반환

// 스트림 기본 설정이 직렬 스트림이기에 sequential 생략 가능

· 스트림의 최종연산 - 조건 검사

- 조건 검사 - allMatch(), anyMatch(), noneMatch()

- 조건에 일치하는 요소 찾기 - findFirst(), findAny()

· 스트림의 최종연산 - reduce() ## 제일 중요!

- 스트림의 요소를 하나씩 줄여가며 누적연산 수행 - reduce() // 스트림의 모든 최종연산은 reduce()로 만들어진다.

// Optional 식과 T 식이 같지만, 스트림이 비어이는 경우 Optional 를 사용해야 하기 때문에!

// reduce가 저렇게 돌아간다는 것만 알면 된다. a = a+b 에 해당하는 연산이 accumulator이다.

● ch14-45~49 collect()와 Collectors

· collect() 와 Collectors // reduce()는 전체에 대해서 리듀싱, collect()는 그룹별 리듀싱

- collect()는 Collector를 매개변수로 하는 스트림의 최종연산

- Collector는 수집(collect)에 필요한 메서드를 정의해놓은 인터페이스

// T 요소를 A에 계속 누적한 다음 R로 변환하여 주는 것이다. supplier와 accumulator가 핵심이다.

-> reduce는 초기값과 누적수행작업이 중요하듯이 Collector도 저장할 곳과 누적방법이 핵심인 것!

// 다른 메서드들은 딱히 중요하지 x

// Collecter 인터페이스를 이미 Collectors에서 구현하였다.

## collect()는 최종연산, Collector는 인터페이스, Collectors는 클래스

· 스트림을 컬렉션, 배열로 전환

// 내가 List를 구현한 특정클래스로 지정하고싶으면 .toCollection(타입::New)를 작성하면 된다.

// toMap은 Key와 Value를 갖기에, p라는 사람에게서 주민번호를 키로 얻고, p라는 사람 자체의 객체를 값으로!

// Stream에 매개변수가 있는 경우와 없는 경우가 있는데, 매개변수가 없는 것은 Object 배열로 반환. 왜냐하면 toArray()가 반환하는 타입은 Object이기에, 원하는 타입으로 반환하고 싶다면 매개변수를 작성해줘야한다.

· 스트림의 통계 – counting(), summingInt()

- 스트림의 통계정보 제공 – counting(0, summingInt(), maxBy(), minBy(),....

// collect를 사용하여 max를 구할 때 남자 그룹, 여자 그룹 1등을 구할 수 있다. => 이게 바로 Collecter의 장점

· 스트림을 리듀싱- reducing() //Collectors가 제공하는, 그룹별 reduce (sum이나 count 등)

- 문자열 스트림의 요소를 모두 연결 – joining() ex) 학생들 이름을 모아서 [a,b,c,...]

● ch 14-50~55 스트림의 그룹화와 분할

· 스트림의 그룹화와 분할 //매개변수는 생각하지말라. // 둘 다 Collectors에 있는 메서드

- partitioningBy()는 스트림을 2분할 한다.

- groupingBy()는 스트림을 n분할한다.

· 스트림의 분할 – partitioningBy()

- 스트림의 요소를 2분할 //groupingBy()도 가능은 하지만, partitioningBy()가 더 빠르다.

// Collectors의 특성으로 인해 성별로 나눈 다음에 카운팅도 가능하다.

예시

1. 2분할 후 counting

2. 2분할 후 max 구하기

3. 다중 분할(2분할하고 또 2분할) Map 안에 또 Map이 있는 것. => Value 안에 또 key, value

· 스트림의 그룹화 – groupingBy() //사용법에 집중

- 스트림의 요소를 그룹화

예시 // partitioningBy()와 사용법은 같으나, mapping 이라는 기능을 추가적으로 사용할 수 있는 것.

1. 다중 그룹화 후 다중 그룹화

2. 다중 그룹화 후 Map을 통해 조건별 다중 그룹화 <학년, 반, 성적>

// grouping 에는 다양한 방법이 있다. 학년별, 반별도 있지만 학년-반별 이렇게 할 수도 있다.

· 스트림의 변환

- 스트림을 기본형 스트림으로 바꾸는 방법,기본형 스트림을 스트림으로 바꾸는 방법

·

·

·

·

·

·

·

·

from http://ing-til-death.tistory.com/69 by ccl(A) rewrite - 2021-10-14 21:28:08