Item 45. Stream

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

슀트림 APIλŠ” λ‹€λŸ‰μ˜ 데이터 처리 μž‘μ—…μ„ μ²˜λ¦¬ν•˜λŠ” 것을 도와 μ£ΌλŠ”λ°, 핡심 좔상 κ°œλ…μ€ μ•„λž˜ 두 가지라고 ν•  수 μžˆλ‹€.

  • μŠ€νŠΈλ¦Όμ€ 데이터 μ›μ†Œμ˜ μœ ν•œ ν˜Ήμ€ λ¬΄ν•œ μ‹œν€€μŠ€λ₯Ό λœ»ν•œλ‹€.

  • 슀트림 νŒŒμ΄ν”„λΌμΈμ€ 이 μ›μ†Œλ“€λ‘œ μˆ˜ν–‰ν•˜λŠ” μ—°μ‚° 단계λ₯Ό ν‘œν˜„ν•œλ‹€.

슀트림 μ•ˆμ˜ 데이터 μ›μ†Œλ“€μ€ 객체 μ°Έμ‘°λ‚˜ κΈ°λ³Έ νƒ€μž… κ°’(int, long double)을 포함할 수 μžˆλ‹€.

슀트림 μ—°μ‚°

μŠ€νŠΈλ¦Όμ€ μ†ŒμŠ€ μŠ€νŠΈλ¦Όμ—μ„œ μ‹œμž‘ν•΄ 쒅단 μ—°μ‚°μœΌλ‘œ λλ‚˜λ©°, κ·Έ 사이에 ν•˜λ‚˜ μ΄μƒμ˜ 쀑간 연산이 μžˆμ„ 수 μžˆλ‹€.

  • 쀑간 μ—°μ‚°(intermediate operation) : μŠ€νŠΈλ¦Όμ„ μ–΄λ– ν•œ λ°©μ‹μœΌλ‘œ λ³€ν™˜ν•˜λŠ” μ—°μ‚°(데이터 μ›μ†Œμ˜ νƒ€μž…μ΄ λ°”λ€” 수 있음)

  • 쒅단 μ—°μ‚°(terminal operation) : 슀트림 νŒŒμ΄ν”„λΌμΈμ—μ„œ κ²°κ³Όλ₯Ό λ„μΆœν•˜λŠ” μ—°μ‚°

슀트림 νŒŒμ΄ν”„λΌμΈμ€ 지연 μ‹€ν–‰λ˜κΈ° λ•Œλ¬Έμ—, 쒅단 연산이 ν˜ΈμΆœλ˜λŠ” μ‹œμ μ— λͺ¨λ“  쀑간 연산이 μ μš©λœλ‹€. λ˜ν•œ 슀트림 APIλŠ” λ©”μ„œλ“œ 연쇄λ₯Ό μ§€μ›ν•˜λŠ” ν”Œλ£¨μ–ΈνŠΈ API(fluent API)이기 λ•Œλ¬Έμ—, νŒŒμ΄ν”„λΌμΈ ν•˜λ‚˜λ₯Ό κ΅¬μ„±ν•˜λŠ” λͺ¨λ“  ν˜ΈμΆœμ„ μ—°κ²°ν•˜μ—¬ 단일 ν‘œν˜„μ‹μœΌλ‘œ λ§Œλ“€ 수 μžˆλ‹€.

κ³Όν•œ 슀트림

μŠ€νŠΈλ¦Όμ„ μ‚¬μš©ν•˜λ©΄ μ½”λ“œκ°€ 간결해지고 가독성이 μ’‹μ•„μ§€λŠ” κ²½μš°κ°€ λ§Žμ§€λ§Œ, κ³Όν•˜κ²Œ μ‚¬μš©ν•˜λŠ” κ²½μš°μ—” 였히렀 μ½”λ“œκ°€ 더 λ³΅μž‘ν•΄μ§ˆ 수 μžˆλ‹€.

// κΈ°μ‘΄ μ½”λ“œ
class Anaagram {
    public static void main(String[] args) throws IOException {
        Path dictionary = Paths.get(args[0]);
        int minGroupSize = Integer.parseInt(args[1]);

        Map<String, Set<String>> groups = new HashMap<>();
        try (Scanner s = new Scanner(dictionary)) {
            while (s.hasNext()) {
                String word = s.next();
                groups.computeIfAbsent(alphabetize(word), (unused) -> new TreeSet<>()).add(word);
            }
        }

        for (Set<String> group : groups.values()) {
            if (group.size() >= minGroupSize) {
                System.out.println(group.size() + ": " + group);
            }
        }
    }

    private static String alphabetize(String s) {
        char[] a = s.toCharArray();
        Arrays.sort(a);
        return new String(a);
    }
}

// Stream μ‚¬μš©
class Anaagram {
    public static void main(String[] args) throws IOException {
        Path dictionary = Paths.get(args[0]);
        int minGroupSize = Integer.parseInt(args[1]);

        try (Stream<String> words = Files.lines(dictionary)) {
            words.collect(groupingBy(word -> word.chars().sorted()
                            .collect(StringBuilder::new, (sb, c) -> sb.append((char) c), StringBuilder::append).toString()))
                    .values().stream().filter(group -> group.size() >= minGroupSize)
                    .map(group -> group.size() + ": " + group).forEach(System.out::println);
        }
    }
}

μ½”λ“œμ˜ 길이만 μ§§μ•„μ‘Œμ„ 뿐, μŠ€νŠΈλ¦Όμ„ μ‚¬μš©ν•œ μͺ½μ˜ μ½”λ“œκ°€ 더 λ³΅μž‘ν•˜κ³  μ΄ν•΄ν•˜κΈ° μ–΄λ ΅λ‹€κ³  λ³Ό 수 μžˆλ‹€. λͺ¨λ“  연산을 μŠ€νŠΈλ¦Όμ—μ„œ μˆ˜ν–‰ν•˜λŠ” 것이 μ•„λ‹ˆλΌ 적절히 μ‚¬μš©ν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€.

import java.nio.file.Files;

class Anaagram {
    public static void main(String[] args) throws IOException {
        Path dictionary = Paths.get(args[0]);
        int minGroupSize = Integer.parseInt(args[1]);

        try (Stream<String> words = Files.lines(dictionary)) {
            words.collect(groupingBy(word -> alphabetize(word)))
                    .values().stream()
                    .filter(group -> group.size() >= minGroupSize)
                    .forEach(group -> System.out.println(group.size() + ": " + group));
        }
    }

    private static String alphabetize(String s) {
        char[] a = s.toCharArray();
        Arrays.sort(a);
        return new String(a);
    }
}

κΈ°λ³Έ νƒ€μž…μ΄ μ•„λ‹Œ 슀트림 μ‚¬μš©

μŠ€νŠΈλ¦Όμ€ 기본적으둜 int, long, double νƒ€μž…λ§Œ μ§€μ›ν•˜λŠ”λ°, μ΄μ™Έμ˜ νƒ€μž…μ„ μ‚¬μš©ν•˜λ©΄ μ˜λ„ν•˜μ§€ μ•Šμ€ λ™μž‘μ΄ λ°œμƒν•  수 μžˆλ‹€.

class Example {

    public static void main(String[] args) {
        // chars() λ©”μ„œλ“œλŠ” IntStream을 λ°˜ν™˜ν•˜κΈ° λ•Œλ¬Έμ— λ°œμƒν•œ 문제
        "Hello world!".chars().forEach(System.out::println); // 72101108...
        
        // ν•΄κ²° 방법, λͺ…μ‹œμ μœΌλ‘œ ν˜•λ³€ν™˜
        "Hello world!".chars().forEach(x -> System.out.print((char) x)); // Hello world!
    }
}

μœ„μ™€ 같이 char νƒ€μž…μ„ μ‚¬μš©ν•  λ•ŒλŠ” λͺ…μ‹œμ μœΌλ‘œ ν˜•λ³€ν™˜μ„ ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€. μ΄λŠ” 가독성이 떨어지고 였λ₯˜κ°€ λ°œμƒν•  κ°€λŠ₯성이 λ†’κΈ° λ•Œλ¬Έμ— μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 것이 μ’‹λ‹€.

μ•Œλ§žλŠ” 슀트림 μ‚¬μš©

μŠ€νŠΈλ¦Όμ„ κ³Όν•˜κ²Œ μ‚¬μš©ν•˜λŠ” 것은 μ•ˆ μ’‹μ§€λ§Œ, μ•„λž˜μ™€ 같은 μƒν™©μ—μ„œλŠ” μŠ€νŠΈλ¦Όμ„ μ‚¬μš©μ„ κ³ λ €ν•΄λ³Ό 수 μžˆλ‹€.

  • μ›μ†Œλ“€μ˜ μ‹œν€€μŠ€λ₯Ό μΌκ΄€λ˜κ²Œ λ³€ν™˜

  • μ›μ†Œλ“€μ˜ μ‹œν€€μŠ€λ₯Ό 필터링

  • μ›μ†Œλ“€μ˜ μ‹œν€€μŠ€λ₯Ό ν•˜λ‚˜μ˜ 연산을 μ‚¬μš©ν•΄ κ²°ν•©(+, concat, min, max λ“±)

  • μ›μ†Œλ“€μ˜ μ‹œν€€μŠ€λ₯Ό μ»¬λ ‰μ…˜μ— λͺ¨μœΌκΈ°(toList, toSet λ“±)

  • μ›μ†Œλ“€μ˜ μ‹œν€€μŠ€μ—μ„œ νŠΉμ • 쑰건을 λ§Œμ‘±ν•˜λŠ” μ›μ†Œλ₯Ό μ°ΎκΈ°(findAny, anyMatch λ“±)

ν•˜μ§€λ§Œ μœ„ 상황이라고 무쑰건 μŠ€νŠΈλ¦Όμ„ μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” 것은 μ•„λ‹ˆκ³ , κ²°κ΅­μ—” 같은 일을 μˆ˜ν–‰ν•˜λŠ” μ½”λ“œλ₯Ό 개인 μ·¨ν–₯으둜 μ„ νƒν•˜λŠ” 것이기 λ•Œλ¬Έμ— λ‘˜ 쀑 더 λ‚˜μ€ 것을 μ„ νƒν•˜λ©΄ λœλ‹€.

Last updated

Was this helpful?