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