Java의 Stream πŸ€”

LibienzΒ·2023λ…„ 11μ›” 21일
1

Stream&Lambda

λͺ©λ‘ 보기
2/2
post-thumbnail

μ•ˆλ…•ν•˜μ„Έμš” πŸ€— λ°±μ—”λ“œ 개발자 λ¦¬λΉ„μ—”μ¦ˆμž…λ‹ˆλ‹€ πŸ‘Š
였늘 ν¬μŠ€νŒ…μ—μ„œλŠ” μ§€λ‚œ ν¬μŠ€νŒ…, μžλ°”μ˜ λžŒλ‹€μ— μ΄μ–΄μ„œ μŠ€νŠΈλ¦Όμ— λŒ€ν•΄μ„œ 닀루어 보렀고 ν•΄μš” 😎

슀트림의 μž₯점과 μŠ€νŠΈλ¦Όμ— μ μš©ν•  수 μžˆλŠ” λ‹€μ–‘ν•œ μ—°μ‚°λ“€ μ†Œκ°œλ“œλ €λ³΄κ² μŠ΅λ‹ˆλ‹€!

Stream μ΄λž€β“

μŠ€νŠΈλ¦Όμ€ 개울, μ‹œλ‚΄ 물쀄기 λ“±μ˜ λœ»μ„ 가지고 μžˆμŠ΅λ‹ˆλ‹€

κ·Έ μ˜λ―Έμ™€ μ—°κ²°ν•΄μ„œ Modern Java in Actionμ΄λΌλŠ” μ±…μ—μ„œλŠ” 데이터 처리 연산을 μ§€μ›ν•˜λ„λ‘ μ†ŒμŠ€μ—μ„œ μΆ”μΆœλœ μ—°μ†λœ μš”μ†ŒλΌκ³  μ„€λͺ…ν•˜κ³  있죠 πŸ€”

μŠ€νŠΈλ¦Όμ€ Java 8λΆ€ν„° λ‹€λŸ‰μ˜ 데이터 처리 μž‘μ—…μ„ 돕기 μœ„ν•΄μ„œ μΆ”κ°€λ˜μ—ˆκ³  데이터 μ†ŒμŠ€κ°€ λ‹€λ₯΄λ”라도 일단 μŠ€νŠΈλ¦Όμ„ μƒμ„±ν•˜κΈ°λ§Œ ν•œλ‹€λ©΄ 과거에 κ·Έ λ°μ΄ν„°μ˜ ν˜•νƒœκ°€ λ¬΄μ—‡μ΄μ—ˆλ˜ 간에 같은 λ°©μ‹μœΌλ‘œ λ‹€λ£° 수 있게 λ©λ‹ˆλ‹€.

이둜써 μŠ€νŠΈλ¦Όμ€ μ½”λ“œμ˜ μž¬μ‚¬μš©μ„±μ΄ λ†’μ•„μ§„λ‹€λΌλŠ” μž₯점과 배열이든 μ»¬λ ‰μ…˜μ΄λ“  νŒŒμΌμ΄λ“  Stream을 λ§Œλ“€μ–΄λ‚΄κΈ°λ§Œ ν•˜λ©΄ λ™μΌν•˜κ²Œ μ²˜λ¦¬ν•  수 있게 λ˜λŠ” μž₯점 λ˜ν•œ κ°€μ§‘λ‹ˆλ‹€ πŸ€—

ν•΄λ‹Ή ν¬μŠ€νŒ…μ€ μŠ€νŠΈλ¦Όμ— μ‚¬μš© 방법에 κ΄€ν•΄μ„œ μ„€λͺ… λ“œλ¦½λ‹ˆλ‹€. μŠ€νŠΈλ¦Όμ— λŒ€ν•œ λ‹€μ–‘ν•œ 연산을 μ†Œκ°œλ“œλ¦¬λŠ”λ° λͺ¨λ“  것을 μ™Έμš°λ €κ³  ν•˜μ‹œκΈ° 보단 λŠλ‚Œμ„ νŒŒμ•…ν•˜μ‹œκ³  μ‹€μ œλ‘œ μ μš©ν•΄λ³΄λ©° λ§₯락과 ν•¨κ»˜ ν•™μŠ΅ν•˜μ‹œλŠ” 것을 μΆ”μ²œ λ“œλ €μš” πŸ‘Š

Stream μ‚¬μš© 방법

μŠ€νŠΈλ¦Όμ€ μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œ λ‹€μŒ 3단계λ₯Ό μ•Œμ•„μ•Ό ν•©λ‹ˆλ‹€!

  1. 슀트림 생성 (데이터 μ†ŒμŠ€λ‘œ λΆ€ν„° μŠ€νŠΈλ¦Όμ„ 생성)
  2. 쀑간 μ—°μ‚° (μ›ν•˜λŠ” ν˜•νƒœλ‘œ 데이터λ₯Ό 가곡)
  3. μ΅œμ’… μ—°μ‚° (μ›ν•˜λŠ” ν˜•νƒœλ‘œ λ°˜ν™˜)

각 연산을 μ‘°ν•©ν•΄μ„œ μ‚¬μš©ν•˜λŠ” μ˜ˆμ‹œ μ„ μ œμ μœΌλ‘œ λ³΄μ—¬λ“œλ¦½λ‹ˆλ‹€ 😊

List<String> names = people.stream() // 생성
						.filter(person -> people.getAge().equals(24)) //쀑간 μ—°μ‚°
						.map(Person::getName)//쀑간 μ—°μ‚°
						.limit(10) //쀑간 μ—°μ‚°
						.toList(); //μ΅œμ’… μ—°μ‚°

자 그럼 μ΄μ œλŠ” 각 λ‹¨κ³„λ³„λ‘œ ν•œλ²ˆ 같이 μ‚΄νŽ΄λ΄…μ‹œλ‹€!

λ³Έ ν¬μŠ€νŠΈμ—μ„œλŠ” λŒ€ν‘œμ μΈ 슀트림 생성 μ†ŒμŠ€μΈ μ»¬λ ‰μ…˜, λ°°μ—΄, 숫자, λžŒλ‹€μ‹μ„ μ˜ˆμ‹œλ‘œ 각 단계λ₯Ό μ„€λͺ…λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€.

Stream 생성

λ¨Όμ € 슀트림 μƒμ„±μž…λ‹ˆλ‹€. 데이터 μ†ŒμŠ€λ‘œ λΆ€ν„° μŠ€νŠΈλ¦Όμ„ μƒμ„±ν•˜λŠ” μ½”λ“œλ₯Ό μ˜ˆμ‹œλ‘œ λ³΄μ—¬λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€.

μ»¬λ ‰μ…˜μœΌλ‘œ λΆ€ν„° 슀트림 μƒμ„±ν•˜κΈ°!

μ»¬λ ‰μ…˜μ€ 이미 μŠ€νŠΈλ¦Όμ„ 생성할 수 μžˆλŠ” λ©”μ„œλ“œ stream()을 μ œκ³΅ν•˜κ³  μžˆλ‹΅λ‹ˆλ‹€.
이λ₯Ό μ‚¬μš©ν•˜λ©΄ μŠ€νŠΈλ¦Όμ„ 생성할 수 μžˆμ–΄μš”!

private final List<Card> cards;
private boolean hasAce() {
	return cards.stream().anyMatch(Card::isAce); // 슀트림 생성 λΆ€λΆ„ 
}

λ°°μ—΄λ‘œ λΆ€ν„° 슀트림 μƒμ„±ν•˜κΈ°!

λ°°μ—΄ μ—­μ‹œ μ •μ˜λ˜μ–΄μžˆλŠ” static methodλ₯Ό μ‚¬μš©ν•¨μœΌλ‘œμ¨ μŠ€νŠΈλ¦Όμ„ 생성할 수 μžˆλ‹΅λ‹ˆλ‹€ πŸ€—

	Arrays.stream(arr)....

μˆ«μžλ‘œλΆ€ν„° 슀트림 μƒμ„±ν•˜κΈ°!

μˆ«μžλ‘œλΆ€ν„°λ„ μŠ€νŠΈλ¦Όμ„ 생성할 수 μžˆμŠ΅λ‹ˆλ‹€! λ‚œμˆ˜μ˜ μŠ€νŠΈλ¦Όμ„ 생성할 μˆ˜λ„ 있고 쑰건에 맞좘 숫자 μŠ€νŠΈλ¦Όμ„ 생성할 μˆ˜λ„ μžˆλŠ”λ°μš” ν•˜λ‚˜μ”© μ‚΄νŽ΄λ³΄μ‹œμ£  😎

  • μž„μ˜μ˜ 수λ₯Ό λ‹€μŒμ²˜λŸΌ 생성할 수 μžˆλ‹€.
IntStream intStream = new Random().ints();
  • νŠΉμ • λ²”μœ„μ˜ μ—°μ†λœ μ •μˆ˜λ₯Ό λ‹€μŒ 처럼 생성할 수 μžˆλ‹€.
IntStream intStream1 = IntStream.range(1,5); //1,2,3,4
IntStream intStream2 = IntStream.rangeClosed(1,5); //1,2,3,4,5
  • νŠΉμ • λ²”μœ„μ˜ λ‚œμˆ˜λ₯Ό λ‹€μŒκ³Ό 같이 생성할 수 μžˆλ‹€.
IntStream limitedStream = new Random().ints(10,1,10); //10μ‚¬μ΄μ¦ˆμ˜ 슀트림 begin 1, end 10
IntStream unlimitedIntStream = new Random.ints(1,10); //begin1, end 10 μ‚¬μ΄μ¦ˆ νŠΉμ • μ•ˆν•¨

λžŒλ‹€μ‹μœΌλ‘œλΆ€ν„° 슀트림 μƒμ„±ν•˜κΈ°

λžŒλ‹€μ‹λ„ κ²°κ΅­ 인자λ₯Ό λ°›μ•„μ„œ returnν•˜λŠ” λ©”μ„œλ“œμ˜ 좕약버전이라고 λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€ (μ •ν™•νžˆλŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ κ΅¬ν˜„μ²΄ κ΄€λ ¨ μ„€λͺ…)
λ”°λΌμ„œ 반볡적으둜 값을 μ „λ‹¬ν•˜κ³  λ°˜ν™˜λ˜λŠ” 값을 λͺ¨μœΌλ©΄ μŠ€νŠΈλ¦Όμ„ 생성할 수 μžˆμŠ΅λ‹ˆλ‹€!
λžŒλ‹€μ‹μœΌλ‘œλΆ€ν„° μŠ€νŠΈλ¦Όμ„ μƒμ„±ν•˜κΈ° μœ„ν•΄μ„œλŠ” iterate λ©”μ„œλ“œλ‚˜ generateλ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.
ν•˜λ‚˜μ”© μ‚΄νŽ΄λ΄…μ‹œλ‹€! λ¨Όμ € iterate πŸ€—

  • iterate은 νŒŒλΌλ―Έν„°λ‘œ μ‹œλ“œ κ°’κ³Ό λžŒλ‹€ 식을 λ°›λŠ”λ‹€.
  • μ‹œλ“œ 값은 λžŒλ‹€μ‹μ— νŒŒλΌλ―Έν„°λ‘œ λ“€μ–΄κ°€λŠ” 제일 첫번째 κ°’μœΌλ‘œ κ·Έλ ‡κ²Œ λ°˜ν™˜λœ κ²°κ³ΌλŠ” λ‹€μ‹œ λžŒλ‹€μ‹μ˜ μž…λ ₯으둜 λ“€μ–΄κ°€κΈ°λ₯Ό λ°˜λ³΅ν•˜κ²Œ λœλ‹€.
Stream.iterate(0, n->n+2)
	.limit(4)
	.forEach(System.out::println); // 0,2,4,6

generate은 μ‹œλ“œ 값이 μ—†λ‹€λŠ” μ μ—μ„œ iterate와 성격을 λ‹¬λ¦¬ν•˜λŠ”λ°μš”! ν•œλ²ˆ μ‚΄νŽ΄λ³΄μ£ 

  • generateλŠ” μ‹œλ“œ κ°’ 없이 λžŒλ‹€μ‹μ˜ κ³„μ‚°κ°’μœΌλ‘œλ§Œ μŠ€νŠΈλ¦Όμ„ μƒμ„±ν•œλ‹€.
Stream<Double> randomStream = Stream.generate(Math::random); 
Stream<Integer> oneStream = Stream.generate(()->1); // 1, 1, 1, 1 ...

Stream 쀑간 μ—°μ‚°

이어 슀트림의 데이터λ₯Ό μ›ν•˜λŠ” ν˜•νƒœλ‘œ κ°€κ³΅ν•˜λŠ” 쀑간 μ—°μ‚° μ†Œκ°œλ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€! μ œκ³΅λ˜λŠ” μ—¬λŸ¬ λ©”μ„œλ“œ κ°€μš΄λ° 제 κΈ°μ€€ 주둜 μ‚¬μš©ν•˜λŠ” 쀑간 μ—°μ‚° λ©”μ„œλ“œ 4κ°€μ§€λ§Œ μ„€λͺ…λ“œλ¦΄κ²Œμš”! πŸ€—

distinct() : μŠ€νŠΈλ¦Όμ—μ„œ μ€‘λ³΅λ˜λŠ” 데이터λ₯Ό 제거

List<String> distinctList = stringList.stream()
     .distinct() //λ¬Έμžμ—΄μ΄ 같은 쀑볡 μ›μ†Œλ₯Ό 제거!
     .collect(Collectors.toList());

filter(Predicate predicate) : 쑰건을 λ§Œμ‘±ν•˜λŠ” λ°μ΄ν„°λ§Œ 남기고 λ‚˜λ¨Έμ§€λ₯Ό μ œμ™Έ

List<Integer> evenNumbers = numberList.stream()
  	 .filter(number -> number % 2 == 0) // 짝수만 필터링
  	 .collect(Collectors.toList());

sorted(Comparator comparator) : μ •λ ¬ κΈ°μ€€μœΌλ‘œ μ •λ ¬ (μ •λ ¬ κΈ°μ€€ μ—†λ‹€λ©΄ κΈ°λ³Έ μ •λ ¬ κΈ°μ€€)

List<String> sortedList = stringList.stream()
     .sorted() // sorted()λ₯Ό μ‚¬μš©ν•˜μ—¬ μ•ŒνŒŒλ²³μˆœμœΌλ‘œ μ •λ ¬
     .collect(Collectors.toList());  

map(Function<T,R> mapper) : μ›ν•˜λŠ” ν•„λ“œλ§Œ λ½‘μ•„λ‚΄κ±°λ‚˜, νŠΉμ • ν˜•νƒœλ‘œ λ³€ν™˜

List<Integer> squaredNumbers = numberList.stream()
    .map(number -> number * number) // map()을 μ‚¬μš©ν•˜μ—¬ 각 숫자λ₯Ό μ œκ³±ν•˜μ—¬ μƒˆλ‘œμš΄ 리슀트 생성
    .collect(Collectors.toList()); 

Stream μ΅œμ’… μ—°μ‚°

λ§ˆμ§€λ§‰μœΌλ‘œ μ›ν•˜λŠ” ν˜•νƒœλ‘œ λ°˜ν™˜ν•˜λ„λ‘ μœ λ„ν•˜λŠ” μ΅œμ’… μ—°μ‚°μž…λ‹ˆλ‹€!
μ΅œμ’… μ—°μ‚°μœΌλ‘œμ¨ μ œκ³΅λ˜λŠ” μ—¬λŸ¬ λ©”μ„œλ“œλ“€κ³Ό κ·Έ μ‚¬μš© λͺ¨μŠ΅μ„ λ³΄μ—¬λ“œλ¦¬κ² μŠ΅λ‹ˆλ‹€ 😊

forEach(Consumer<? super T> action) : 슀트림의 데이터λ₯Ό μ†Œλͺ¨ν•˜λ©° 주둜 좜λ ₯ν•˜λŠ” μš©λ„λ‘œ μ‚¬μš©

//stream의 각 μ›μ†Œλ₯Ό 좜λ ₯
stringList.stream().forEach(element -> System.out.println(element));

allMatch(Predicate<? super T> predicate) : λͺ¨λ“  μš”μ†Œκ°€ μΌμΉ˜ν•˜λ©΄ true

// λͺ¨λ‘ μ§μˆ˜μΈμ§€ 확인
boolean allEven = numberList.stream().allMatch(number -> number % 2 == 0);

anyMatch(Predicate<? super T> predicate) : ν•˜λ‚˜μ˜ μš”μ†Œλ„ μΌμΉ˜ν•˜λ©΄ true

// ν™€μˆ˜μΈ μš”μ†Œκ°€ μžˆλŠ”μ§€ 확인
boolean anyOdd = numberList.stream().anyMatch(number -> number % 2 != 0);

noneMatch(Predicate<? super T> predicate) : λͺ¨λ“  μš”μ†Œκ°€ λΆˆμΌμΉ˜ν•˜λ©΄ true

// μ–΄λ–€ μš”μ†Œλ„ ν™€μˆ˜κ°€ μ•„λ‹Œμ§€ 확인
boolean noneOdd = numberList.stream().noneMatch(number -> number % 2 != 0);

findFirst() : 쑰건에 μΌμΉ˜ν•˜λŠ” 첫 번째 μš”μ†Œλ₯Ό λ°˜ν™˜

Optional<String> firstFilteredElement = stringList.stream()
                .filter(s -> s.startsWith("o")) // "o"둜 μ‹œμž‘ν•˜λŠ” λ¬Έμžμ—΄λ§Œ 선택 (쀑간 μ—°μ‚°)
                .findFirst();                   // μ„ νƒλœ λ¬Έμžμ—΄ μ€‘μ—μ„œ 첫 번째 μš”μ†Œ μ°ΎκΈ° (μ΅œμ’… μ—°μ‚°)

findAny(): 쑰건에 μΌμΉ˜ν•˜λŠ” μš”μ†Œλ₯Ό ν•˜λ‚˜ λ°˜ν™˜

Optional<Integer> anyEvenNumber = numberList.stream()
                .filter(number -> number % 2 == 0)  // 짝수인 숫자만 선택 (쀑간 μ—°μ‚°)
                .findAny();                           // μ„ νƒλœ 숫자 μ€‘μ—μ„œ μž„μ˜μ˜ μš”μ†Œ μ°ΎκΈ° (μ΅œμ’… μ—°μ‚°)

collect(Collector collector) : 슀트림의 μš”μ†Œλ₯Ό μˆ˜μ§‘ν•΄ μ›ν•˜λŠ” ν˜•νƒœλ‘œ λ°˜ν™˜
- Collecotr νƒ€μž…μ„ νŒŒλΌλ―Έν„°λ‘œ λ°›μŒ
- CollectorλŠ” μΈν„°νŽ˜μ΄μŠ€μΈλ° μˆ˜λ§Žμ€ 좔상 λ©”μ„œλ“œλ₯Ό μ •μ˜ν•΄μ•Ό collect()의 νŒŒλΌλ―Έν„°λ‘œ μ‚¬μš©ν•  수 있음.
- ν•˜μ§€λ§Œ μˆ˜λ§Žμ€ 좔상 λ©”μ„œλ“œλ₯Ό 일일이 μ •μ˜ν•  μˆ˜λŠ” μ—†λ‹€.
- κ·Έλž˜μ„œ static λ©”μ„œλ“œλ‘œ λ§Žμ€ 것을 미리 μ •μ˜ν•΄μ€€ Collectorsλ₯Ό 주둜 μ΄μš©ν•¨.
- μ˜ˆμ‹œ .collect(Collectors.toList()); 데이터λ₯Ό μˆ˜μ§‘ν•΄μ„œ 리슀트 ν˜•νƒœλ‘œ λ°˜ν™˜
- μ˜ˆμ‹œ .collect(Collectors.groupingBy(person -> person.getCountry())); person의 countryλ³„λ‘œ κ·Έλ£Ήν™” ν•˜μ—¬ 맡으둜 λ°˜ν™˜

슀트림 정리

μ§€κΈˆκΉŒμ§€ 슀트림이 3가지 연산을 ν†΅ν•΄μ„œ μ‚¬μš©λ  수 μžˆμŒμ„ μ•Œμ•„λ³΄μ•˜κ³  λ‹¨κ³„λ³„λ‘œ μŠ€νŠΈλ¦Όμ„ μƒμ„±ν•˜λŠ” 법, μŠ€νŠΈλ¦Όμ— 쀑간 μ—°μ‚°μžλ₯Ό λ¨Ήμ—¬μ„œ λ‚΄κ°€ μ›ν•˜λŠ” λ°μ΄ν„°λ‘œ κ°€κ³΅ν•˜λŠ” 법, μ΅œμ’… 연산을 톡해 λ‚΄κ°€ μ›ν•˜λŠ” ν˜•νƒœλ‘œ λ°›μ•„μ˜€λŠ” 법을 μ•Œμ•„λ³΄μ•˜μŠ΅λ‹ˆλ‹€ πŸ€—

μ—°μ‚°μ˜ μ’…λ₯˜κ°€ λ§Žμ€ 만큼 ν•„μš”ν•  λ•Œλ§ˆλ‹€ 찾아보며 λ§₯λ½μ†μ—μ„œ μ‚¬μš©λ˜λŠ” λͺ¨μŠ΅μ„ 반볡적으둜 읡히며 μ΅μˆ™ν•΄μ Έμ•Ό ν•˜κ² λ„€μš” πŸ€”

profile
좔상보닀 상세에 μ§‘μ°©ν•˜λŠ” 개발자 리비(λ¦¬λΉ„μ—”μ¦ˆ)μž…λ‹ˆλ‹€ πŸ€—

0개의 λŒ“κΈ€