[JAVA] 23. λ©”μ„œλ“œ μ°Έμ‘°, 슀트림(Stream)

2022. 6. 5. 13:38ㆍJAVA/μžλ°”μ˜ 정석

728x90

 

1️⃣ λ©”μ„œλ“œ μ°Έμ‘° 

λžŒλ‹€μ‹μ—μ„œ λžŒλ‹€μ‹μ΄ ν•˜λ‚˜μ˜ λ©”μ„œλ“œλ§Œ ν˜ΈμΆœν•˜λŠ” κ²½μš°μ—λŠ” 'λ©”μ„œλ“œ μ°Έμ‘°(method reference)'λΌλŠ” λ°©λ²•μœΌλ‘œ λžŒλ‹€μ‹μ„ κ°„λž΅νžˆ ν•  수 μžˆλ‹€. 

ν΄λž˜μŠ€μ΄λ¦„::λ©”μ„œλ“œμ΄λ¦„ 

-> Function μΈν„°νŽ˜μ΄μŠ€μ— μ§€μ •λœ 지넀릭 νƒ€μž…μœΌλ‘œ λžŒλ‹€μ‹μ˜ 일뢀λ₯Ό μΆ”μΈ‘ν•  수 있기 λ•Œλ¬Έμ— μƒλž΅ν•  수 μžˆλ‹€. 

μ°Έμ‘°λ³€μˆ˜ f의 νƒ€μž…λ§Œ 봐도 λžŒλ‹€μ‹μ΄ ν•œκ°œμ˜ String을 λ§€κ°œλ³€μˆ˜λ‘œ λ°›λŠ” 것을 μ•Œ 수 있기 λ•Œλ¬Έμ— λžŒλ‹€μ‹μ˜ λ§€κ°œλ³€μˆ˜λ“€μ€ 없어도 λœλ‹€. 

 

-> μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜λŠ” λžŒλ‹€μ‹λ„ λ©”μ„œλ“œ 참쑰둜 λ³€ν™˜ν•  수 μžˆλ‹€. 

 

-> λ§€κ°œλ³€μˆ˜κ°€ μžˆλŠ” μƒμ„±μžλΌλ©΄ λ§€κ°œλ³€μˆ˜μ˜ κ°œμˆ˜μ— 따라 μ•Œλ§žμ€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€. 

 

-> 배열을 생성할 λ•ŒλŠ” λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό μ‚¬μš©ν•œ κ²ƒμœΌλ‘œ 이거 많이 μ‚¬μš©ν•œλ‹€κ³  ν•œλ‹€. 

 

 

2️⃣ 슀트림 (Stream) μ΄λž€? 

: λ‹€μ–‘ν•œ 데이터 μ†ŒμŠ€λ₯Ό ν‘œμ€€ν™”λœ λ°©λ²•μœΌλ‘œ 닀루기 μœ„ν•œ 것 

μ§€κΈˆκΉŒμ§€ μš°λ¦¬λŠ” 수 λ§Žμ€ 데이터λ₯Ό 닀루기 μœ„ν•΄ μ»¬λ ‰μ…˜μ΄λ‚˜ 배열에 데이터λ₯Ό λ‹΄κ³  μ›ν•˜λŠ” κ²°κ³Όλ₯Ό μ–»κΈ° μœ„ν•΄ forλ¬Έμ΄λ‚˜ iterator μ΄μš©ν•΄ μ½”λ“œλ₯Ό μž‘μ„±ν–ˆλ‹€. κ·ΈλŸ¬λ‚˜ μ΄λŸ¬ν•œ λ°©μ‹μœΌλ‘œ μž‘μ„±λœ μ½”λ“œλŠ” μ•Œμ•„λ³΄κΈ° μ–΄λ ΅κ³  κΈΈλ©°, μž¬μ‚¬μš©μ„±λ„ 떨어진닀. 

 

또 λ‹€λ₯Έ λ¬Έμ œλŠ” 데이터 μ†ŒμŠ€λ§ˆλ‹€ λ‹€λ₯Έ λ°©μ‹μœΌλ‘œ 닀뀄야 ν•œλ‹€λŠ” 점이닀!

Collectionμ΄λ‚˜ iterator와 같은 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ΄μš©ν•΄ μ»¬λ ‰μ…˜μ„ λ‹€λ£¨λŠ” 방식을 ν‘œμ€€ν™”ν•˜κΈ°λŠ” ν–ˆμ§€λ§Œ, 각 μ»¬λ ‰μ…˜ ν΄λž˜μŠ€λŠ” 같은 κΈ°λŠ₯의 λ©”μ„œλ“œλ“€μ΄ μ€‘λ³΅ν•΄μ„œ μ •μ˜λ˜μ–΄ μžˆλ‹€. 

ex) Collecions.sort(), Arrays.sort() 

 

μ΄λŸ¬ν•œ λ¬Έμ œμ λ“€μ„ ν•΄κ²°ν•˜κΈ° μœ„ν•΄ λ§Œλ“  것이 μŠ€νŠΈλ¦Όμ΄λ‹€. 

μŠ€νŠΈλ¦Όμ€ λ°μ΄ν„°μ†ŒμŠ€λ₯Ό μΆ”μƒν™”ν•˜κ³  데이터λ₯Ό λ‹€λ£¨λŠ”λ° 자주 μ‚¬μš©λ˜λŠ” λ©”μ„œλ“œλ“€μ„ μ •μ˜ν•΄ λ†“μ•˜λ‹€. 

λ°μ΄ν„°μ†ŒμŠ€λ₯Ό μΆ”μƒν™”ν•˜μ˜€λ‹€λŠ” 것은 데이터 μ†ŒμŠ€κ°€ λ¬΄μ—‡μ΄λ˜ 간에 같은 λ°©μ‹μœΌλ‘œ λ‹€λ£° 수 있게 λ˜μ—ˆλ‹€λŠ” 것과 μ½”λ“œμ˜ μž¬μ‚¬μš©μ„±μ΄ λ†’μ•„μ§„λ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€. 

μŠ€νŠΈλ¦Όμ„ μ΄μš©ν•˜λ©΄ λ°°μ—΄μ΄λ‚˜ μ»¬λ ‰μ…˜λΏλ§Œ μ•„λ‹ˆλΌ νŒŒμΌμ— μ €μž₯된 데이터도 λͺ¨λ‘ 같은 λ°©μ‹μœΌλ‘œ λ‹€λ£° 수 μžˆλ‹€. 

 

- 슀트림 μ—°μ‚° 

: 슀트림이 μ œκ³΅ν•˜λŠ” λ‹€μ–‘ν•œ 연산을 μ΄μš©ν•΄μ„œ λ³΅μž‘ν•œ μž‘μ—…λ“€μ„ κ°„λ‹¨νžˆ μ²˜λ¦¬ν•  수 μžˆλ‹€. 

슀트림이 μ œκ³΅ν•˜λŠ” 연산은 쀑간 μ—°μ‚°κ³Ό μ΅œμ’… μ—°μ‚°μœΌλ‘œ λΆ„λ₯˜ν•  수 μžˆλŠ”λ°, 쀑간 연산은 μ—°μ‚°κ²°κ³Όλ₯Ό 슀트림으둜 λ°˜ν™˜ν•˜κΈ° λ•Œλ¬Έμ— 쀑간 연산을 μ—°μ†ν•΄μ„œ μ—°κ²°ν•  수 μžˆλ‹€. 

μ΅œμ’… 연산은 슀트림의 μš”μ†Œλ₯Ό μ†Œλͺ¨ν•˜λ©΄μ„œ 연산을 μˆ˜ν–‰ν•˜λ―€λ‘œ 단 ν•œλ²ˆλ§Œ 연산인 κ°€λŠ₯ν•˜λ‹€.

 

 

3️⃣ 슀트림 νŠΉμ§• 

 

- μŠ€νŠΈλ¦Όμ€ 데이터 μ†ŒμŠ€λ₯Ό λ³€κ²½ν•˜μ§€ μ•ŠλŠ”λ‹€. (원본 λ³€κ²½x)

μŠ€νŠΈλ¦Όμ€ 데이터 μ†ŒμŠ€λ‘œλΆ€ν„° 데이터λ₯Ό 읽기만 ν•  뿐, 데이터 μ†ŒμŠ€λ₯Ό λ³€κ²½ν•˜μ§€ μ•ŠλŠ”λ‹€. 

 

- μŠ€νŠΈλ¦Όμ€ μΌνšŒμš©μ΄λ‹€. 

μŠ€νŠΈλ¦Όμ€ iterator처럼 μΌνšŒμš©μ΄λ‹€.  Iterator둜 μ»¬λ ‰μ…˜μ˜ μš”μ†Œλ₯Ό λͺ¨λ‘ 읽고 λ‚˜λ©΄ λ‹€μ‹œ μ‚¬μš©ν•  수 μ—†λŠ” 것 처럼, μŠ€νŠΈλ¦Όλ„ ν•œλ²ˆ μ‚¬μš©ν•˜λ©΄ λ‹«ν˜€μ„œ λ‹€μ‹œ μ‚¬μš©ν•  수 μ—†λ‹€. 

 

- μŠ€νŠΈλ¦Όμ€ μž‘μ—…μ„ λ‚΄λΆ€ 반볡으둜 μ²˜λ¦¬ν•œλ‹€.

μŠ€νŠΈλ¦Όμ„ μ΄μš©ν•œ μž‘μ—…μ΄ κ°„κ²°ν•  수 μžˆλŠ” λΉ„κ²° 쀑 ν•˜λ‚˜κ°€ λ°”λ‘œ λ‚΄λΆ€ λ°˜λ³΅μ΄λ‹€. 

λ‚΄λΆ€ λ°˜λ³΅μ΄λΌλŠ” 것은 λ°˜λ³΅λ¬Έμ„ λ©”μ„œλ“œ 내뢀에 숨길 수 μžˆλŠ” 것을 μ˜λ―Έν•œλ‹€. 

-> forEachλŠ” λ©”μ„œλ“œ μ•ˆμœΌλ‘œ for문을 넣은 것이닀. 

 

- μ§€μ—°λœ μ—°μ‚°

슀트림 μ—°μ‚°μ—μ„œ ν•œ 가지 μ€‘μš”ν•œ 점은 μ΅œμ’… 연산이 μˆ˜ν–‰λ˜κΈ° μ „κΉŒμ§€λŠ” 쀑간 연산이 μˆ˜ν–‰λ˜μ§€ μ•ŠλŠ”λ‹€λŠ” 것이닀. 

μŠ€νŠΈλ¦Όμ— λŒ€ν•΄ distinct()λ‚˜ sort() 같은 쀑간 연산을 ν˜ΈμΆœν•΄λ„ 즉각적인 연산이 μˆ˜ν–‰λ˜λŠ” 것이 μ•„λ‹ˆλΌλŠ” 것이닀. 

단지 쀑간 연산을 ν˜ΈμΆœν•˜λŠ” 것은 μ–΄λ–€ μž‘μ—…μ΄ μˆ˜ν–‰λ˜μ–΄μ•Ό ν•˜λŠ”μ§€ μ§€μ •ν•΄μ£ΌλŠ” 것일 뿐이닀. 

μ΅œμ’… 연산이 μˆ˜ν–‰λ˜μ–΄μ•Ό λΉ„λ‘œμ†Œ 슀트림의 μš”μ†Œλ“€μ΄ 쀑간 연산을 거쳐 μ΅œμ’… μ—°μ‚°μ—μ„œ μ†Œλͺ¨λœλ‹€. 

 

- Stream<Integer> 와 IntStream

μš”μ†Œμ˜ νƒ€μž…μ΄ T인 μŠ€νŠΈλ¦Όμ€ 기본적으둜 Stream<T>μ΄μ§€λ§Œ, μ˜€ν† λ°•μ‹± & μ–Έλ°•μ‹±μœΌλ‘œ μΈν•œ λΉ„νš¨μœ¨μ„ 쀄이기 μœ„ν•΄ 데이터 μ†ŒμŠ€λ₯Ό κΈ°λ³Έν˜•μœΌλ‘œ λ‹€λ£¨λŠ” 슀트림, IntStream, LongStream, DoubleStream이 μ œκ³΅λœλ‹€. 

일반적으둜 Stream<Integer>λŒ€μ‹  IntStream을 μ‚¬μš©ν•˜λŠ” 것이 더 효율적이고, IntStreamμ—λŠ” int νƒ€μž…μ˜ κ°’μœΌλ‘œ μž‘μ—…ν•˜λŠ”λ° μœ μš©ν•œ λ©”μ„œλ“œλ“€μ΄ ν¬ν•¨λ˜μ–΄ μžˆλ‹€. 

 

- 병렬 슀트림

슀트림으둜 데이터λ₯Ό λ‹€λ£° λ•Œμ˜ μž₯점 쀑 ν•˜λ‚˜κ°€ λ°”λ‘œ λ³‘λŸ΄ μ²˜λ¦¬κ°€ μ‰½λ‹€λŠ” 것이닀. 

 

 

 

4️⃣ 슀트림 λ§Œλ“€κΈ° 

1. 슀트림 λ§Œλ“€κΈ°
2. 쀑간연산 (0~ n번)
3. μ΅œμ’… μ—°μ‚° (0~1번)

 

- μ»¬λ ‰μ…˜

μ»¬λ ‰μ…˜μ˜ 졜고 쑰상 Collection에 stream()이 μ •μ˜λ˜μ–΄ μžˆλ‹€. 

λ”°λΌμ„œ Collection의 μžμ†μΈ List와 Set을 κ΅¬ν˜„ν•œ μ»¬λ ‰μ…˜ ν΄λž˜μŠ€λ“€μ€ λͺ¨λ‘ 이 λ©”μ„œλ“œλ₯Ό 슀트림으둜 생성할 수 μžˆλ‹€. 

stream()은 ν•΄λ‹Ή μ»¬λ ‰μ…˜μ„ μ†ŒμŠ€λ‘œ ν•˜λŠ” μŠ€νŠΈλ¦Όμ„ λ°˜ν™˜ν•œλ‹€. 

Stream<T> Collection.stream() -> μ»¬λ ‰μ…˜μ„ 슀트림으둜 λ³€ν™˜ 

μ΄λ•Œ forEach()λŠ” 슀트림의 μš”μ†Œλ₯Ό μ†Œλͺ¨ν•˜λ©΄μ„œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜κΈ° λŒ€λ¬Έμ— 같은 μŠ€νŠΈλ¦Όμ— forEach()λ₯Ό 두 번 ν˜ΈμΆœν•  수 μ—†λ‹€. 

λ”°λΌμ„œ 슀트림의 μš”μ†Œλ₯Ό ν•œ 번 더 ν˜ΈμΆœν•˜λ €λ©΄ μŠ€νŠΈλ¦Όμ„ μƒˆλ‘œ μƒμ„±ν•΄μ•Όν•œλ‹€. 

❗️ forEach()에 μ˜ν•΄ 슀트림의 μš”μ†Œκ°€ μ†Œλͺ¨λ˜λŠ” 것이지, μ†ŒμŠ€μ˜ μš”μ†Œκ°€ μ†Œλͺ¨λ˜λŠ” 것은 μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— 같은 μ†ŒμŠ€λ‘œλΆ€ν„° λ‹€μ‹œ μŠ€νŠΈλ¦Όμ„ 생성할 수 μžˆλ‹€. 

 

 

- λ°°μ—΄ 

배열을 μ†ŒμŠ€λ‘œ ν•˜λŠ” μŠ€νŠΈλ¦Όμ„ μƒμ„±ν•˜λŠ” λ©”μ„œλ“œλŠ” Streamκ³Ό Arrays에 static λ©”μ„œλ“œλ‘œ μ •μ˜λ˜μ–΄ μžˆλ‹€. 

 

 

- νŠΉμ • λ²”μœ„μ˜ μ •μˆ˜ 

IntStreamκ³Ό LongStream은 μ§€μ •λœ λ²”μœ„μ˜ μ—°μ†λœ μ •μˆ˜λ₯Ό 슀트림으둜 μƒμ„±ν•΄μ„œ λ°˜ν™˜ν•˜λŠ” range() 와 rangeClosed()λ₯Ό 가지고 μžˆλ‹€.

range()의 경우 κ²½κ³„μ˜ 끝인 endκ°€ λ²”μœ„μ— ν¬ν•¨λ˜μ§€ μ•Šκ³  rangeClosed()의 κ²½μš°λŠ” endκ°€ λ²”μœ„μ— ν¬ν•¨λœλ‹€. 

 

 

- μž„μ˜μ˜ 수

λ‚œμˆ˜λ₯Ό μƒμ„±ν•˜λŠ”λ° μ‚¬μš©ν•˜λŠ” Randomν΄λž˜μŠ€μ—λŠ” μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œλ“€μ΄ ν¬ν•¨λ˜μ–΄ μžˆλ‹€, 

이 λ©”μ„œλ“œλ“€μ€ ν•΄λ‹Ή νƒ€μž…μ˜ λ‚œμˆ˜λ“€λ‘œ 이루어진 μŠ€νŠΈλ¦Όμ„ λ°˜ν™˜ν•œλ‹€. 

이 λ©”μ„œλ“œλ“€μ΄ λ°˜ν™˜ν•˜λŠ” μŠ€νŠΈλ¦Όμ€ 크기가 정해지지 μ•Šμ€ λ¬΄ν•œ 슀트림이기 λ•Œλ¬Έμ— limit()κ³Ό 같이 μ‚¬μš©ν•˜μ—¬ 슀트림의 크기λ₯Ό μ œν•œν•΄ μ£Όμ–΄μ•Ό ν•œλ‹€. 

❗️ limit()은 슀트림의 개수λ₯Ό μ§€μ •ν•˜λŠ”λ° μ‚¬μš©λ˜λ©°, λ¬΄ν•œ μŠ€νŠΈλ¦Όμ„ μœ ν•œ 슀트림으둜 λ§Œλ“€μ–΄μ€€λ‹€. 

 

- λžŒλ‹€μ‹ iterate(), generate()

Stream클래슀의 iterate()와 generate()λŠ” λžŒλ‹€μ‹μ„ λ§€κ°œλ³€μˆ˜λ‘œ λ°›μ•„μ„œ, 이 λžŒλ‹€μ‹μ— μ˜ν•΄ κ³„μ‚°λ˜λŠ” 값듀을 μš”μ†Œλ‘œ ν•˜λŠ” λ¬΄ν•œ μŠ€νŠΈλ¦Όμ„ μƒμ„±ν•œλ‹€. 

iterate() λŠ” 씨앗값(seed)으둜 μ§€μ •λœ κ°’λΆ€ν„° μ‹œμž‘ν•΄μ„œ, λžŒλ‹€μ‹ f에 μ˜ν•΄μ„œ κ³„μ‚°λœ κ²°κ³Όλ₯Ό λ‹€μ‹œ seedκ°’μœΌλ‘œ ν•΄μ„œ 계산을 λ°˜λ³΅ν•œλ‹€. 

generate()λŠ” iterate() 처럼 λžŒλ‹€μ‹μ— μ˜ν•΄ κ³„μ‚°λ˜λŠ” 값을 μš”μ†Œλ‘œ ν•˜λŠ” λ¬΄ν•œ μŠ€νŠΈλ¦Όμ„ μƒμ„±ν•΄μ„œ λ°˜ν™˜ν•˜μ§€λ§Œ, iterate()와 같이 이전 κ²°κ³Όλ₯Ό μ΄μš©ν•΄μ„œ λ‹€μŒ μš”μ†Œλ₯Ό κ³„μ‚°ν•˜μ§€ μ•ŠλŠ”λ‹€. 

generate()에 μ •μ˜λœ λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ€ Supplier<T>μ΄λ―€λ‘œ λ§€κ°œλ³€μˆ˜κ°€ μ—†λŠ” λžŒλ‹€μ‹λ§Œμ„ ν—ˆμš©ν•œλ‹€. 

 

- 파일

java.nio.file.FilesλŠ” νŒŒμΌμ„ λ‹€λ£¨λŠ”λ° ν•„μš”ν•œ μœ μš©ν•œ λ©”μ„œλ“œλ“€μ„ μ œκ³΅ν•˜λŠ”λ°, list()λŠ” μ§€μ •λœ 디렉토리(dir)에 μžˆλŠ” 파일의 λͺ©λ‘μ„ μ†ŒμŠ€λ‘œ ν•˜λŠ” μŠ€νŠΈλ¦Όμ„ μƒμ„±ν•΄μ„œ λ°˜ν™˜ν•œλ‹€. 

lines()λŠ” 파일의 ν•œ ν–‰(line)을 μš”μ†Œλ‘œ ν•˜λŠ” μŠ€νŠΈλ¦Όμ„ μƒμ„±ν•˜λŠ” λ©”μ„œλ“œλ„ μžˆλ‹€. 

 

 

- 빈 슀트림

μš”μ†Œκ°€ ν•˜λ‚˜λ„ μ—†λŠ” λΉ„μ–΄μžˆλŠ” μŠ€νŠΈλ¦Όμ„ 생성할 μˆ˜λ„ μžˆλ‹€. 

μŠ€νŠΈλ¦Όμ— 연산을 μˆ˜ν–‰ν•œ κ²°κ³Όκ°€ ν•˜λ‚˜λ„ 없을 λ•Œ null보닀 빈 μŠ€νŠΈλ¦Όμ„ λ°˜ν™˜ν•˜λŠ” 것이 λ‚«λ‹€. 

Stream emptyStream = Stream.empty(); 
long count = emptyStream.count();  // count 의 값은 0 

count()λŠ” 슀트림의 μš”μ†Œμ˜ 개수λ₯Ό λ°˜ν™˜ν•œλ‹€. 

 

 

 

 

 

 

 

 

 

 

 

728x90