λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

πŸ“šμ½μ€ μ±… 정리/μ΄νŽ™ν‹°λΈŒμžλ°”

[μ΄νŽ™ν‹°λΈŒ μžλ°”] 7μž₯ : λžŒλ‹€μ™€ 슀트림

μžλ°” 8μ—μ„œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€, λžŒλ‹€, λ©”μ„œλ“œ μ°Έμ‘°λΌλŠ” κ°œλ…μ΄ μΆ”κ°€λ˜μ—ˆλ‹€. (ν•¨μˆ˜ 객체 μ‰½κ²Œ μ‚¬μš©)

이와 ν•¨κ»˜ 슀트림 API μΆ”κ°€λ‘œ 데이터 μ›μ†Œμ˜ μ‹œν€€μŠ€ 처리λ₯Ό 라이브러리 μ°¨μ›μ—μ„œ μ§€μ›ν•˜κΈ° μ‹œμž‘ν–ˆλ‹€.

μ•„μ΄ν…œ 42 : 읡λͺ… ν΄λž˜μŠ€λ³΄λ‹€λŠ” λžŒλ‹€λ₯Ό μ‚¬μš©ν•˜λΌ

  1. μ˜ˆμ „μ— μžλ°”μ—μ„œ ν•¨μˆ˜ νƒ€μž… ν‘œν˜„ ⇒ 좔상 λ©”μ„œλ“œλ₯Ό ν•˜λ‚˜λ§Œ 담은 μΈν„°νŽ˜μ΄μŠ€(or μΆ”μƒν΄λž˜μŠ€) μ‚¬μš©
  2. JDK 1.1 λ“±μž₯ ν›„ ‘읡λͺ… 클래슀'κ°€ ν•¨μˆ˜ 객체λ₯Ό λ§Œλ“œλŠ” μ£Όμš”μˆ˜λ‹¨
    List<String> words = Arrays.asList(args);
    Collections.sort(words, new Comparator<String > () { 
    	public int compare(String s1, String s2) { 
    		return Integer.compare(s1.length(), s2.length()); 
    	} 
    });
    
  3. ‘읡λͺ…ν΄λž˜μŠ€λŠ” μ½”λ“œκ°€ λ„ˆλ¬΄ κΈΈμ–΄ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ— μ ν•©ν•˜μ§€ μ•ŠμŒ’

μžλ°” 8μ—μ„œ ‘μΆ”μƒλ©”μ„œλ“œ ν•˜λ‚˜μ˜ μΈν„°νŽ˜μ΄μŠ€'λŠ” νŠΉλ³„ν•˜κ²Œ μ‚¬μš©ν•˜κ²Œ λ˜μ—ˆλ‹€. ⇒ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” μΈμŠ€ν„΄μŠ€λ₯Ό ‘λžŒλ‹€μ‹'을 μ‚¬μš©ν•΄ λ§Œλ“€ 수 μžˆλ‹€. ⇒ κ°„κ²°ν•œ μ½”λ“œ

List<String> words = Arrays.asList(args);
Collections.sort(words,
                (s1, s2) -> Integer.compare(s1.length(), s2.length()));

λžŒλ‹€μ˜ λ§€κ°œλ³€μˆ˜λ₯Ό μ‚΄νŽ΄λ³΄λ©΄ νƒ€μž…μ΄ λͺ…μ‹œλ˜μ–΄μžˆμ§€ μ•Šλ‹€. μ΄λŠ” μ»΄νŒŒμΌλŸ¬κ°€ νƒ€μž…μΆ”λ‘ μ„ 해쀀것이닀. (상황에 따라 νƒ€μž… λͺ…μ‹œ ν•„μš”)

  • νƒ€μž… μΆ”λ‘ 
    • 보톡 μ»΄νŒŒμΌλŸ¬λŠ” νƒ€μž…μ„ μΆ”λ‘ ν•  λ•Œ μ œλ„€λ¦­μ—μ„œ 정보λ₯Ό μ–»λŠ”λ‹€. λ§Œμ•½ Listκ°€ λ‘œνƒ€μž…μ΄μ˜€λ‹€λ©΄ νƒ€μž… 좔둠에 μ‹€νŒ¨ν•΄ 컴파일 μ—λŸ¬κ°€ λ°œμƒν–ˆμ„ 것이닀.
  • λΉ„κ΅μž 생성 λ©”μ„œλ“œ
  • Collections.sort(words, comparingInt(String::length));
  • μžλ°” 8에 μΆ”κ°€λœ sort λ©”μ„œλ“œλͺ¨λ‘ λΉ„κ΅μž μƒμ„±λ©”μ„œλ“œκ°€ λžŒλ‹€μ‹ μžλ¦¬μ— λ“€μ–΄κ°„λ‹€.
  • words.sort(comparingInt(String::length));

μ‹€μš©μ  μ‚¬μš©

λžŒλ‹€κ°€ μΆ”κ°€λ˜λ©΄μ„œ ν•¨μˆ˜κ°μ²΄λ₯Ό μ‹€μš©μ μœΌλ‘œ μ‚¬μš©ν•  수 있게 λ˜μ—ˆλ‹€.

λžŒλ‹€λ₯Ό μ‚¬μš©ν•˜λ©΄ κ°’λ§ˆλ‹€ λ‹€λ₯΄κ²Œ λ™μž‘ν•˜λŠ” μ½”λ“œλ₯Ό μ‰½κ²Œ κ΅¬ν˜„ν•  수 μžˆλ‹€.(μž₯점)

public enum Operation {
    PLUS  ("+", (x, y) -> x + y),
    MINUS ("-", (x, y) -> x - y),
    TIMES ("*", (x, y) -> x * y),
    DIVIDE("/", (x, y) -> x / y);

    private final String symbol;
    private final DoubleBinaryOperator op;

    Operation(String symbol, DoubleBinaryOperator op) {
        this.symbol = symbol;
        this.op = op;
    }

    @Override public String toString() { return symbol; }

    public double apply(double x, double y) {
        return op.applyAsDouble(x, y);
    }

    // μ•„μ΄ν…œ 34의 메인 λ©”μ„œλ“œ (215μͺ½)
    public static void main(String[] args) {
        double x = Double.parseDouble(args[0]);
        double y = Double.parseDouble(args[1]);
        for (Operation op : Operation.values())
            System.out.printf("%f %s %f = %f%n",
                    x, op, y, op.apply(x, y));
    }
}

μœ„ μ½”λ“œλŠ” symbol값을 μ •μ˜ν•˜κ³  DoubleBinaryOperatorλΌλŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό 톡해 μ‰½κ²Œ λ™μž‘μ„ κ΅¬ν˜„ν•΄μ„œ μ£Όμž…ν•΄λ‘μ—ˆλ‹€. μ΄λŠ” μƒμˆ˜λ³„ 클래슀 λͺΈμ²΄ κ΅¬ν˜„λ³΄λ‹€ κ΅¬ν˜„μ€ νŽΈν•˜μ§€λ§Œ 이름이 μ—†κ³  λ¬Έμ„œν™”λ₯Ό ν•˜μ§€ λͺ»ν•œλ‹€.(단점)

λžŒλ‹€ ν•œκ³„

  • λžŒλ‹€λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ—μ„œλ§Œ 쓰인닀. 좔상 ν΄λž˜μŠ€μ—μ„œλŠ” 읡λͺ… 클래슀λ₯Ό μ¨μ•Όν•œλ‹€.
  • λžŒλ‹€λŠ” μžμ‹ μ„ μ°Έμ‘°ν•  수 μ—†λ‹€. (λžŒλ‹€μ˜ thisλŠ” λ°”κΉ₯ μΈμŠ€ν„΄μŠ€λ₯Ό 가리킴)
  • λžŒλ‹€λ₯Ό μ§λ ¬ν™”ν•˜λŠ” 일은 극히 μ‚Όκ°€μž (κ΅¬ν˜„λ³„ 직렬화가 λ‹€λ₯Ό 수 μžˆλ‹€)

λžŒλ‹€λŠ” μžλ°”μ—μ„œ ν•¨μˆ˜ 객체λ₯Ό μ‰½κ²Œ ν‘œν˜„ν•  수 μžˆμ–΄ μžλ°” ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ˜ 지평을 μ—΄μ—ˆλ‹€.

μ•„μ΄ν…œ 43 : λžŒλ‹€λ³΄λ‹€λŠ” λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό μ‚¬μš©ν•˜λΌ

λžŒλ‹€μ˜ μž₯점은 간결함!!

κ·Έ μž₯점을 λ”μš± κ·ΉλŒ€ν™” μ‹œν‚¨ 것이 λ°”λ‘œ ‘λ©”μ„œλ“œ μ°Έμ‘°’

  • ν•˜μ§€λ§Œ μƒλž΅μ„ 많이 ν•˜λ―€λ‘œ μ μ ˆν•˜κ²Œ μ‚¬μš©ν•  것

제λͺ© μ—†μŒ

-핡심정리-

λ©”μ„œλ“œ μ°Έμ‘° μͺ½μ΄ 짧고 λͺ…ν™•ν•˜λ‹€λ©΄ λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό μ“°κ³ , 그렇지 μ•Šμ„ λ•Œλ§Œ λžŒλ‹€λ₯Ό μ‚¬μš©ν•˜λΌ

μ•„μ΄ν…œ 44 : ν‘œμ€€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λΌ

μžλ°”μ˜ λžŒλ‹€ μ§€μ›μœΌλ‘œ 인해 API μž‘μ„± λͺ¨λ²”사둀도 λ³€ν™”ν•˜μ˜€λ‹€.

μƒμœ„ 클래슀 κΈ°λ³Έ λ©”μ„œλ“œλ₯Ό μž¬μ •μ˜ν•΄ λ™μž‘μ„ κ΅¬ν˜„ν•˜λŠ” ‘ν…œν”Œλ¦Ώ λ©”μ„œλ“œ νŒ¨ν„΄'은 ν˜„λŒ€μ μΈ ν•΄λ²•μœΌλ‘œ ν•¨μˆ˜ 객체λ₯Ό λ°›λŠ” 정적 νŒ©ν„°λ¦¬λ‚˜ μƒμ„±μž 제곡으둜 μ‚¬μš©ν•  수 있게 λ˜μ—ˆλ‹€.

**‘ν•¨μˆ˜ 객체'**λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ λ°›λŠ” μƒμ„±μžλ‚˜ λ©”μ„œλ“œλ₯Ό 더 μ‚¬μš©ν•˜κ²Œ λ˜μ—ˆλ‹€.

μžλ°”λŠ” λ‹€μ–‘ν•œ μΈμˆ˜μ™€ λ°˜ν™˜κ°’μ„ μ§€μ›ν•˜λŠ” ‘ν‘œμ€€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€'λ₯Ό μ œκ³΅ν•œλ‹€. (μš©λ„μ— λ§žλ‹€λ©΄ 직접 κ΅¬ν˜„ν•˜μ§€λ§ κ³  μ‚¬μš©ν•˜λΌ)

 

ν‘œμ€€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μ˜ˆμ‹œ

UnaryOperator<T> T apply(T t) String::toLowerCase
BinaryOperator<T> T apply(T t1, T t2) BigInteger::add
Predicate<T> boolean test(T t) Collection::isEmpty
Function<T, R> R apply(T t) Arrays::asList
Supplier<T> T get() Instant::now
Consumer<T> void accept(T t) System.out::println

μœ„ μ˜ˆμ‹œ 외에도 int, long, double용으둜 λ³€ν˜•ν•œ IntPredicate(intλ₯Ό λ°›μ•„ μ°Έ/거짓 νŒλ‹¨) λ“±μ˜ λ³€ν˜•μ΄ 생긴닀.

인수 2κ°œμ”©μ„ λ°›λŠ” BiConsumer<T, U>와 같이 λ³€ν˜•μ΄ 생길 μˆ˜λ„ μžˆλ‹€.

μ΄λŸ¬ν•œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” 무렀 43κ°œλ‚˜ λœλ‹€. λͺ¨λ‘ μ™ΈμšΈ ν•„μš”λŠ” μ—†μ§€λ§Œ 자주 μ“°λŠ” νŒ¨ν„΄μ€ κΈ°μ–΅ν•΄λ‘μž.

  • ν‘œμ€€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” κΈ°λ³Έ νƒ€μž…λ§Œ μ§€μ›ν•˜λ―€λ‘œ λ°•μ‹± νƒ€μž…μ„ λ„£μ–΄ μ„±λŠ₯을 μ €ν•˜μ‹œν‚€μ§€ 말자

 

-직접 μž‘μ„±μ΄ ν•„μš”ν•œ 경우-

  • ν‘œμ€€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ— μš©λ„κ°€ λ§žλŠ” 게 없을 λ•Œ 예λ₯Ό λ“€μ–΄ λ§€κ°œλ³€μˆ˜ 3개 λ˜λŠ” 검사 μ˜ˆμ™Έλ₯Ό λ˜μ§€λŠ” 경우
  • Comparator<T> 같은 경우
    • 자주 쓰이며, 이름 μžμ²΄κ°€ μš©λ„λ₯Ό λͺ…ν™•νžˆ μ„€λͺ…ν•˜λŠ” 경우
    • λ°˜λ“œμ‹œ 따라야 ν•˜λŠ” κ·œμ•½μ΄ μžˆλŠ” 경우
    • μœ μš©ν•œ λ””ν΄νŠΈ λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•  수 μžˆλŠ” 경우

직접 μž‘μ„±ν•œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ—λŠ” ‘@FunctionalInterface’ μ• λ„ˆν…Œμ΄μ…˜μ΄ 달렀 있고 μ‚¬μš©ν•΄μ•Όλ§Œ ν•œλ‹€.

이λ₯Ό μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” ‘@Override’ μ‚¬μš©μ΄μœ μ™€ λΉ„μŠ·ν•˜λ‹€.

  1. 이λ₯Ό μ‚¬μš©ν•˜λŠ” μ΄μ—κ²Œ μΈν„°νŽ˜μ΄μŠ€κ°€ λžŒλ‹€μš©μœΌλ‘œ μ„€κ³„λœ κ²ƒμž„μ„ μ•Œλ¦Ό
  2. ν•΄λ‹Ή μΈν„°νŽ˜μ΄μŠ€κ°€ μΆ”μƒλ©”μ„œλ“œλ₯Ό 였직 ν•˜λ‚˜λ§Œ 가지고 μžˆμ„ λ•Œ 컴파일 λ˜κ²Œν•¨
  3. 2λ²ˆμ„ 톡해 λˆ„κ΅°κ°€ μ‹€μˆ˜λ‘œ λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•˜μ§€ λͺ»ν•˜κ²Œ 막을 수 있음

-핡심 정리-

μžλ°”λ„ λžŒλ‹€λ₯Ό μ§€μ›ν•˜λ‹ˆ 이제 API μ„€κ³„μ‹œ μž…λ ₯κ°’κ³Ό λ°˜ν™˜κ°’μ— ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μ„ ν™œμš©ν•˜λΌ. (ν‘œμ€€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ or 직접 κ΅¬ν˜„ν•œ μΈν„°νŽ˜μ΄μŠ€)

μ•„μ΄ν…œ 45 : μŠ€νŠΈλ¦Όμ€ μ£Όμ˜ν•΄μ„œ μ‚¬μš©ν•˜λΌ

μŠ€νŠΈλ¦Όμ€ λ‹€λŸ‰μ˜ 데이터 μ²˜λ¦¬μž‘μ—…μ„ λ•κ³ μž μžλ°” 8에 μΆ”κ°€λ˜μ—ˆλ‹€.

슀트림 νŒŒμ΄ν”„λΌμΈμ€ 쀑간연산 후에 쒅단 μ—°μ‚°μœΌλ‘œ λλ‚œλ‹€. λ˜ν•œ 지연 평가가 λ˜μ–΄ ν‰κ°€λŠ” 쒅단 연산이 호좜될 λ•Œ 이뀄진닀.

μŠ€νŠΈλ¦Όμ„ κ³Όν•˜κ²Œ μ‚¬μš©ν•˜λ©΄ ν”„λ‘œκ·Έλž¨ 전체가 단 ν•œμ€„μ—λ„ ν‘œν˜„λ  수 μžˆμ§€λ§Œ λ‚˜μ™€ 거의 λŒ€λΆ€λΆ„ μ‚¬λžŒλ“€μ΄ μ½”λ“œλ₯Ό μ΄ν•΄ν•˜κΈ° μ–΄λ €μ›Œμ§„λ‹€. ⇒ 슀트림이 κ³Όν•˜λ©΄ μ½κ±°λ‚˜ μœ μ§€λ³΄μŠ€κ°€ νž˜λ“  ν”„λ‘œκ·Έλž¨μ΄ λœλ‹€.

λ”°λΌμ„œ, κΈ°μ‘΄ μ½”λ“œλŠ” μŠ€νŠΈλ¦Όμ„ μ‚¬μš©ν•˜λ„λ‘ λ¦¬νŒ©ν† λ§ ν•˜λ˜, μƒˆ μ½”λ“œκ°€ λ‚˜μ•„ 보일 λ•Œλ§Œ λ°˜μ˜ν•˜μž.

쀑간 μ—°μ‚°μœΌλ‘œ μ‚¬μš©ν•œ flatMap은 슀트림의 μ›μ†Œ 각각을 ν•˜λ‚˜μ˜ 슀트림으둜 λ§€ν•‘ν•œ λ‹€μŒ λ‹€μ‹œ κ·Έ μŠ€νŠΈλ¦Όμ„ ν•˜λ‚˜μ˜ 슀트림으둜 ν•©μΉœλ‹€. (쀑첩 λžŒλ‹€ μ‚¬μš©)

    // μ½”λ“œ 45-5 데카λ₯΄νŠΈ κ³± 계산을 슀트림 λ°©μ‹μœΌλ‘œ κ΅¬ν˜„ (276μͺ½)
    private static List<Card> newDeck() {
        return Stream.of(Suit.values())
                .flatMap(suit ->
                        Stream.of(Rank.values())
                                .map(rank -> new Card(suit, rank)))
                .collect(toList());
    }

μ•„μ΄ν…œ 46 : μŠ€νŠΈλ¦Όμ—μ„œλŠ” λΆ€μž‘μš© μ—†λŠ” ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λΌ

슀트림의 핡심은 계산을 일련의 λ³€ν™˜μœΌλ‘œ μž¬κ΅¬μ„±ν•˜λŠ” 것이닀.

  • 각 λ³€ν™˜ λ‹¨κ³„λŠ” 이전 λ‹¨κ³„μ˜ κ²°κ³Όλ₯Ό λ°›μ•„ μ²˜λ¦¬ν•˜λŠ” 순수 ν•¨μˆ˜
    • μˆœμˆ˜ν•¨μˆ˜ : 였직 μž…λ ₯만이 결과에 영ν–₯을 μ£ΌλŠ” ν•¨μˆ˜

forEachλŠ” 슀트림 계산 κ²°κ³Όλ₯Ό 보고할 λ•Œλ§Œ μ‚¬μš©ν•˜κ³  κ³„μ‚°ν•˜λŠ” λ°μ—λŠ” μ“°μ§€λ§μž.

μŠ€νŠΈλ¦Όμ„ μ˜¬λ°”λ₯΄κ²Œ μ‚¬μš©ν•˜λ €λ©΄ Collectorλ₯Ό μ•Œμ•„λ‘¬μ•Όν•œλ‹€.

  • toList, toSet, toMap, groupingBy, joining ..etc

p.277 μ˜ˆμ‹œλ“€μ„ 자주 보며 읡히자.

μ•„μ΄ν…œ 47 : λ°˜ν™˜ νƒ€μž…μœΌλ‘œλŠ” μŠ€νŠΈλ¦Όλ³΄λ‹€ μ»¬λ ‰μ…˜μ΄ λ‚«λ‹€

λ°˜ν™˜ νƒ€μž…μœΌλ‘œ μŠ€νŠΈλ¦Όλ³΄λ‹€ μ»¬λ ‰μ…˜ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ“΄λ‹€.

μ›μ†Œ μ‹œν€€μŠ€λ₯Ό λ°˜ν™˜ν•˜λŠ” 곡개 API의 λ°˜ν™˜ νƒ€μž…μ—λŠ” Collectionμ΄λ‚˜ κ·Έ ν•˜μœ„ νƒ€μž…μ„ μ“°λŠ” 게 일반적으둜 μ΅œμ„ μ΄λ‹€.

  • Collection μΈν„°νŽ˜μ•—λŠ” Iterable의 ν•˜μœ„ νƒ€μž…μ΄κ³ , stream λ©”μ„œλ“œλ„ μ œκ³΅ν•œλ‹€.
  • ν•˜μ§€λ§Œ, 단지 μ»¬λ ‰μ…˜μ„ λ°˜ν™˜ν•œλ‹€λŠ” 이유둜 덩치 큰 μ‹œν€€μŠ€λ₯Ό λ©”λͺ¨λ¦¬μ— μ˜¬λ €μ„œλŠ” μ•ˆλœλ‹€.

μ»¬λ ‰μ…˜μ„ λ°˜ν™˜ν•˜λŠ” 게 λΆˆκ°€λŠ₯ν•˜λ©΄ 슀트림과 Iterable 쀑 더 μžμ—°μŠ€λŸ¬μš΄ 것을 λ°˜ν™˜ν•˜λΌ

μ•„μ΄ν…œ 48 : 슀트림 λ³‘λ ¬ν™”λŠ” μ£Όμ˜ν•΄μ„œ μ μš©ν•˜λΌ

λ™μ‹œμ„± ν”„λ‘œκ·Έλž¨μ„ μ˜¬λ°”λ₯΄κ²Œ μž‘μ„±ν•˜λŠ” 것은 맀우 μ–΄λ ΅λ‹€. 병렬 슀트림 νŒŒμ΄ν”„λΌμΈ ν”„λ‘œκ·Έλž˜λ°μ—μ„œλ„ μ΄λŠ” λ‹€λ₯Όλ°”κ°€ μ—†λ‹€.

μŠ€νŠΈλ¦Όμ„ 잘λͺ» λ³‘λ ¬ν™”ν•˜λ©΄ μ„±λŠ₯이 λ‚˜λΉ μ§€κ±°λ‚˜ μ˜ˆμƒμΉ˜ λͺ»ν•œ κ²°κ³Όλ‚˜ λ™μž‘μ΄ λ°œμƒν•  수 μžˆλ‹€.

정말 쑰건만 잘 μ§€μΌœμ§€λ©΄ parallelλ©”μ„œλ“œ 호좜 ν•˜λ‚˜λ‘œ μ—„μ²­λ‚œ μ„±λŠ₯ ν–₯상을 얻을 수 있긴 ν•˜λ‹€.