๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป ์ดํŽ™ํ‹ฐ๋ธŒ ์ž๋ฐ” - ๋žŒ๋‹ค์™€ ์ŠคํŠธ๋ฆผ

65274 ๋‹จ์–ด Java2022๋…์„œ2022

7์žฅ - ๋žŒ๋‹ค์™€ ์ŠคํŠธ๋ฆผ


๐Ÿ’ก ์ต๋ช… ํด๋ž˜์Šค๋ณด๋‹ค๋Š” ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

โ€œ์ต๋ช… ํด๋ž˜์Šค๋Š” (ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์•„๋‹Œ) ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ๋งŒ ์‚ฌ์šฉํ•˜๋ผโ€

1. ์ต๋ช… ํด๋ž˜์Šค

  • ์ž๋ฐ”8 ์ด์ „์—๋Š” ํ•จ์ˆ˜ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ์ฃผ์š” ์ˆ˜๋‹จ์œผ๋กœ ์ต๋ช… ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ์—ˆ์Œ
    • ์ต๋ช… ํด๋ž˜์Šค ๋ฐฉ์‹์€ ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด ๊ธธ๋‹ค..
// ์ต๋ช… ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ํ•จ์ˆ˜ ๊ฐ์ฒด๋กœ ์‚ฌ์šฉ - ๋‚ก์€ ๊ธฐ๋ฒ•์ด๋‹ค!
Collections.sort(words, new Comparator<String>() {
    public int compare(String s1, String s2) {
        return Integer.compare(s1.length(), s2.length());
    }
});
System.out.println(words);
Collections.shuffle(words);

2. ๋žŒ๋‹ค

  • ์ž๋ฐ”8์— ์™€์„œ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋žŒ๋‹ค์‹์„ ์ด์šฉํ•ด ์งง๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ๋จ.
    • ์•„๋ž˜ ์ฝ”๋“œ์˜ ๋žŒ๋‹ค์‹์„ ์‚ดํŽด๋ณด๋ฉด ๋งค๊ฐœ๋ณ€์ˆ˜, ๋ฐ˜ํ™˜๊ฐ’์˜ ํƒ€์ž…์ด ๋ช…์‹œ๋˜์–ด ์žˆ์ง€ ์•Š์Œ.
      • ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํƒ€์ž…์„ ์•Œ์•„์„œ ์ถ”๋ก ํ•ด ์คŒ.
      • ์ปดํŒŒ์ผ๋Ÿฌ์˜ ํƒ€์ž… ์ถ”๋ก  ๊ทœ์น™์€ ๋งค์šฐ ๋ณต์žกํ•˜๋ฏ€๋กœ ์ž˜ ์•Œ์ง€ ๋ชปํ•ด๋„ ์ƒ๊ด€ ์—†์Œ
    • ํƒ€์ž…์„ ๋ช…์‹œํ•ด์•ผ ์ฝ”๋“œ๊ฐ€ ๋” ๋ช…ํ™•ํ•  ๋•Œ๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š”, ์•„๋ž˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ๋ชจ๋“  ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…์€ ์ƒ๋žตํ•˜์ž.
// ์ฝ”๋“œ 42-2 ๋žŒ๋‹ค์‹์„ ํ•จ์ˆ˜ ๊ฐ์ฒด๋กœ ์‚ฌ์šฉ - ์ต๋ช… ํด๋ž˜์Šค ๋Œ€์ฒด 
Collections.sort(words,
        (s1, s2) -> Integer.compare(s1.length(), s2.length()));
System.out.println(words);
Collections.shuffle(words);
  • ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•ด ์ƒ์ˆ˜๋ณ„ ๋™์ž‘์„ ๊ตฌํ˜„ํ•œ ์—ด๊ฑฐ ํƒ€์ž… ์˜ˆ์‹œ
    • ์—ด๊ฑฐ ํƒ€์ž… ์ƒ์ˆ˜์˜ ๋™์ž‘์„ ํ‘œํ˜„ํ•œ ๋žŒ๋‹ค๋ฅผ DoubleBinaryOperator ์ธํ„ฐํŽ˜์ด์Šค ๋ณ€์ˆ˜์— ํ• ๋‹นํ•จ.
    • DoubleBinaryOperator ์ธํ„ฐํŽ˜์ด์Šค๋Š” double ํƒ€์ž… ์ธ์ˆ˜ 2๊ฐœ๋ฅผ ๋ฐ›์•„ double ํƒ€์ž… ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•จ.
// ํ•จ์ˆ˜ ๊ฐ์ฒด(๋žŒ๋‹ค)๋ฅผ ์ธ์Šคํ„ด์Šค ํ•„๋“œ์— ์ €์žฅํ•ด ์ƒ์ˆ˜๋ณ„ ๋™์ž‘์„ ๊ตฌํ˜„ํ•œ ์—ด๊ฑฐ ํƒ€์ž…
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);
    }

}
  • ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ง์•„์•ผ ํ•  ๊ฒฝ์šฐ
    • ์ฝ”๋“œ ์ž์ฒด๋กœ ๋™์ž‘์ด ๋ช…ํ™•ํžˆ ์„ค๋ช…๋˜์ง€ ์•Š๊ฑฐ๋‚˜ ์ฝ”๋“œ ์ค„ ์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ ๋•Œ.
      • ๋žŒ๋‹ค๋Š” ์ด๋ฆ„์ด ์—†๊ณ  ๋ฌธ์„œํ™”๋„ ๋ชป ํ•˜๊ธฐ ๋•Œ๋ฌธ.
      • ๋žŒ๋‹ค๋Š” ํ•œ ์ค„์ผ ๋•Œ ๊ฐ€์žฅ ์ข‹๊ณ , ๊ธธ์–ด์•ผ ์„ธ ์ค„ ์•ˆ์— ๋๋‚ด๋Š” ๊ฒŒ ์ข‹์Œ
    • ์ž์‹ ์„ ์ฐธ์กฐํ•ด์•ผํ•  ๊ฒฝ์šฐ
      • ๋žŒ๋‹ค๋Š” ์ž์‹ ์„ ์ฐธ์กฐํ•  ์ˆ˜ ์—†์Œ.
      • ๋žŒ๋‹ค์—์„œ thisํ‚ค์›Œ๋“œ๋Š” ๋ฐ”๊นฅ ์ธ์Šคํ„ด์Šค, ์ต๋ช… ํด๋ž˜์Šค์—์„œ์˜ this๋Š” ์ž์‹ 


๐Ÿ’ก ๋žŒ๋‹ค๋ณด๋‹ค๋Š” ๋ฉ”์„œ๋“œ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

โ€œ๋ฉ”์„œ๋“œ ์ฐธ์กฐ ์ชฝ์ด ์งง๊ณ  ๋ช…ํ™•ํ•˜๋‹ค๋ฉด ๋ฉ”์„œ๋“œ ์ฐธ์กฐ๋ฅผ ์“ฐ๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์„ ๋•Œ๋งŒ ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•˜๋ผโ€

1. ๋žŒ๋‹ค๋ฅผ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ๋กœ

  • ๋ฉ”์†Œ๋“œ ์ฐธ์กฐ(method reference) : ๋žŒ๋‹ค ํ‘œํ˜„์‹์ด ๋‹จ ํ•˜๋‚˜์˜ ๋ฉ”์†Œ๋“œ๋งŒ์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ์— ํ•ด๋‹น ๋žŒ๋‹ค ํ‘œํ˜„์‹์—์„œ ๋ถˆํ•„์š”ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์คŒ
  • ํ•จ์ˆ˜ ๊ฐ์ฒด๋ฅผ ๋žŒ๋‹ค๋ณด๋‹ค ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์˜ˆ์‹œ
// map.merge๋ฅผ ์ด์šฉํ•ด ๊ตฌํ˜„ํ•œ ๋นˆ๋„ํ‘œ - ๋žŒ๋‹ค ๋ฐฉ์‹๊ณผ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ ๋ฐฉ์‹์„ ๋น„๊ตํ•ด๋ณด์ž.
public class Freq {
    public static void main(String[] args) {
        Map<String, Integer> frequencyTable = new TreeMap<>();
        
        for (String s : args)
            frequencyTable.merge(s, 1, (count, incr) -> count + incr); // ๋žŒ๋‹ค
        System.out.println(frequencyTable);

        frequencyTable.clear();
        for (String s : args)
            frequencyTable.merge(s, 1, Integer::sum); // ๋ฉ”์„œ๋“œ ์ฐธ์กฐ
        System.out.println(frequencyTable);

    }
}
  • ๋ฉ”์„œ๋“œ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํŽธ์ด ๋ณดํ†ต์€ ๋” ์งง๊ณ  ๊ฐ„๊ฒฐํ•จ
  • ๋•Œ๋กœ๋Š” ๋žŒ๋‹ค์—์„œ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ด๋ฆ„ ์ž์ฒด๊ฐ€ ํ”„๋กœ๊ทธ๋ž˜๋จธ์—๊ฒŒ ์ข‹์€ ๊ฐ€์ด๋“œ๊ฐ€ ๋˜๊ธฐ๋„ ํ•จ.

2. 5๊ฐ€์ง€ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ ์œ ํ˜•

๋ฉ”์„œ๋“œ ์ฐธ์กฐ ์œ ํ˜•์˜ˆ์‹œ๋žŒ๋‹ค ํ‘œํ˜„
์ •์ Integer::parseIntstr โ†’ Integer.parseInt(str)
ํ•œ์ •์ (์ธ์Šคํ„ด์Šค)Instant.now()::isAfterInstant then = Instant.now();
t โ†’ then.isAfter(t)
๋น„ํ•œ์ •์ (์ธ์Šคํ„ด์Šค)String::toLowerCasestr โ†’ str.toLowerCase()
ํด๋ž˜์Šค ์ƒ์„ฑ์žTreeMap<K, V>::new() โ†’ new TreeMap<K, V>()
๋ฐฐ์—ด ์ƒ์„ฑ์žint[]::newlen โ†’ new int[len]


๐Ÿ’ก ํ‘œ์ค€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

โ€œ๋ณดํ†ต์€ java.util.function ํŒจํ‚ค์ง€์˜ ํ‘œ์ค€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์€ ์„ ํƒโ€

1. ํ‘œ์ค€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค

  • java.util.function ํŒจํ‚ค์ง€๋ฅผ ๋ณด๋ฉด ๋‹ค์–‘ํ•œ ์šฉ๋„์˜ ํ‘œ์ค€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋‹ด๊ฒจ ์žˆ์Œ.
  • ํ•„์š”ํ•œ ์šฉ๋„์— ๋งž๋Š” ๊ฒŒ ์žˆ๋‹ค๋ฉด, ์ง์ ‘ ๊ตฌํ˜„ํ•˜์ง€ ๋ง๊ณ  ํ‘œ์ค€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™œ์šฉํ•˜์ž
  • ๊ธฐ๋ณธ ์ธํ„ฐํŽ˜์ด์Šค 6๊ฐœ
์ธํ„ฐํŽ˜์ด์Šคํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์˜ˆ์„ค๋ช…
UnaryOperatorT apply(T t)String::toLowerCase๋ฐ˜ํ™˜๊ฐ’๊ณผ ์ธ์ˆ˜์˜ ํƒ€์ž…์ด ๊ฐ™์€ ํ•จ์ˆ˜(์ธ์ˆ˜ 1๊ฐœ)
BinaryOperatorT apply(T t1, T t2)BigInteger::add๋ฐ˜ํ™˜๊ฐ’๊ณผ ์ธ์ˆ˜์˜ ํƒ€์ž…์ด ๊ฐ™์€ ํ•จ์ˆ˜(์ธ์ˆ˜ 2๊ฐœ)
Predicateboolean test(T t)Collection::isEmpty์ธ์ˆ˜ ํ•˜๋‚˜๋ฅผ ๋ฐ›์•„ boolean์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
Function<T, R>R apply(T t)Arrays::asList์ธ์ˆ˜์™€ ๋ฐ˜ํ™˜ ํƒ€์ž…์ด ๋‹ค๋ฅธ ํ•จ์ˆ˜
SupplierT get()Instance::now์ธ์ˆ˜๋ฅผ ๋ฐ›์ง€ ์•Š๊ณ  ๊ฐ’์„ ๋ฐ˜ํ™˜(ํ˜น์€ ์ œ๊ณต)ํ•˜๋Š” ํ•จ์ˆ˜
Consumervoid accept(T t)System.out::println์ธ์ˆ˜๋ฅผ ํ•˜๋‚˜ ๋ฐ›๊ณ  ๋ฐ˜ํ™˜๊ฐ’์€ ์—†๋Š”(ํŠนํžˆ ์ธ์ˆ˜๋ฅผ ์†Œ๋น„ํ•˜๋Š” ) ํ•จ์ˆ˜

2. ์ „์šฉ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค

  • ํ‘œ์ค€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ์ „์šฉ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•˜๋Š” ๋•Œ๋Š” ์–ธ์ œ์ผ๊นŒ?
    • ์•„๋ž˜ ์„ธ ๊ฐ€์ง€ ์กฐ๊ฑด ์ค‘ ํ•˜๋‚˜์ด์ƒ์„ ๋งŒ์กฑํ•  ๋•Œ.
      1. ์ž์ฃผ ์“ฐ์ด๋ฉฐ, ์ด๋ฆ„ ์ž์ฒด๊ฐ€ ์šฉ๋„๋ฅผ ๋ช…ํ™•ํžˆ ์„ค๋ช…ํ•ด์ค€๋‹ค.
      2. ๋ฐ˜๋“œ์‹œ ๋”ฐ๋ผ์•ผ ํ•˜๋Š” ๊ทœ์•ฝ์ด ์žˆ๋‹ค.
      3. ์œ ์šฉํ•œ ๋””ํดํŠธ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ex) Compartor<T> ์ธํ„ฐํŽ˜์ด์Šค
    • ์ด ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๊ตฌ์กฐ์ ์œผ๋กœ ToIntBiFunction<T, U> ์™€ ๋™์ผํ•จ.
    • ์ด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋…์ž์ ์œผ๋กœ ์‚ด์•„๋‚จ์€ ์ด์œ 
      • ์„ธ๊ฐ€์ง€ ์กฐ๊ฑด์„ ๋ชจ๋‘ ๋งŒ์กฑํ•จ.
      1. API์—์„œ ๊ต‰์žฅํžˆ ์ž์ฃผ ์“ฐ์ด๋ฉฐ ์ด๋ฆ„์ด ์šฉ๋„๋ฅผ ๋ช…ํ™•ํžˆ ์„ค๋ช…ํ•จ
      2. ๊ตฌํ˜„ํ•˜๋Š” ์ชฝ์—์„œ ๋ฐ˜๋“œ์‹œ ์ง€์ผœ์•ผ ํ•  ๊ทœ์•ฝ์„ ๋‹ด๊ณ  ์žˆ์Œ.
      3. ๋น„๊ต์ž๋“ค์„ ๋ณ€ํ™˜ํ•˜๊ณ  ์กฐํ•ฉํ•ด์ฃผ๋Š” ์œ ์šฉํ•œ ๋””ํดํŠธ ๋ฉ”์„œ๋“œ๋“ค์„ ๋‹ด๊ณ  ์žˆ์Œ.
  • ์ „์šฉ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ž‘์„ฑํ•  ๋•Œ
    1. ์ž์‹ ์ด ์ž‘์„ฑํ•˜๋Š” ๊ฒŒ โ€˜์ธํ„ฐํŽ˜์ด์Šคโ€™์ž„์„ ๋ช…์‹ฌํ•ด์•ผ ํ•จ.(์ฃผ์˜ํ•ด์„œ ์„ค๊ณ„ํ•ด์•ผ ํ•จ)
    2. ํ•ญ์ƒ @FunctionalInterface ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ผ.
  • @FunctionalInterface ์–ด๋…ธํ…Œ์ด์…˜์˜ ๊ธฐ๋Šฅ
    1. ํ•ด๋‹น ํด๋ž˜์Šค์˜ ์ฝ”๋“œ๋‚˜ ์„ค๋ช… ๋ฌธ์„œ๋ฅผ ์ฝ์„ ์ด์—๊ฒŒ ๊ทธ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋žŒ๋‹ค์šฉ์œผ๋กœ ์„ค๊ณ„๋œ ๊ฒƒ์ž„์„ ์•Œ๋ ค์คŒ
    2. ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค์ง ํ•˜๋‚˜๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ์ปดํŒŒ์ผ๋˜๊ฒŒ ํ•ด์คŒ
      • ์œ ์ง€๋ณด์ˆ˜ ๊ณผ์ •์—์„œ ๋ˆ„๊ตฐ๊ฐ€ ์‹ค์ˆ˜๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋ง‰์•„์คŒ.


๐Ÿ’ก ์ŠคํŠธ๋ฆผ์€ ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•˜๋ผ

โ€œ์ŠคํŠธ๋ฆผ๊ณผ ๋ฐ˜๋ณต ์ค‘ ์–ด๋Š ์ชฝ์ด ๋‚˜์€์ง€ ํ™•์‹ ํ•˜๊ธฐ ์–ด๋ ต๋‹ค๋ฉด ๋‘˜ ๋‹ค ํ•ด๋ณด๊ณ  ๋” ๋‚˜์€ ์ชฝ์„ ํƒํ•˜๋ผโ€

1. ์ŠคํŠธ๋ฆผ๊ณผ ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ

  • ์ŠคํŠธ๋ฆผ(stream)์ด๋ž€?
    • ๋ฐ์ดํ„ฐ ์›์†Œ์˜ ์œ ํ•œ ํ˜น์€ ๋ฌดํ•œ ์‹œํ€€์Šค(sequence)
  • ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ(stream pipeline)์ด๋ž€?
    • ์ŠคํŠธ๋ฆผ์˜ ์›์†Œ๋“ค๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ์—ฐ์‚ฐ ๋‹จ๊ณ„๋ฅผ ํ‘œํ˜„
    • ์†Œ์Šค ์ŠคํŠธ๋ฆผ์—์„œ ์‹œ์ž‘ํ•ด ์ข…๋‹จ ์—ฐ์‚ฐ(terminal operation)์œผ๋กœ ๋๋‚˜๋ฉฐ, ๊ทธ ์‚ฌ์ด์— ํ•˜๋‚˜ ์ด์ƒ์˜ ์ค‘๊ฐ„ ์—ฐ์‚ฐ(intermediate operation)์ด ์žˆ์„ ์ˆ˜ ์žˆ์Œ.
      • ๊ฐ ์ค‘๊ฐ„ ์—ฐ์‚ฐ์€ ์ŠคํŠธ๋ฆผ์„ ์–ด๋– ํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ณ€ํ™˜(transform)ํ•จ
    • ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ์€ ์ง€์—ฐ ํ‰๊ฐ€๋จ. ํ‰๊ฐ€๋Š” ์ข…๋‹จ ์—ฐ์‚ฐ์ด ํ˜ธ์ถœ๋  ๋•Œ ์ด๋ค„์ง€๋ฉฐ, ์ข…๋‹จ ์—ฐ์‚ฐ์— ์“ฐ์ด์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ ์›์†Œ๋Š” ๊ณ„์‚ฐ์— ์“ฐ์ด์ง€ ์•Š์Œ.
      • 1๊ฐœ ์ด์ƒ์˜ ์ค‘๊ฐ„์—ฐ์‚ฐ๋“ค์€ ๊ณ„์†ํ•ฉ์ณ์ง„ ํ›„ ์ข…๋‹จ์—ฐ์‚ฐ ์‹œ ์ˆ˜ํ–‰๋œ๋‹ค๋Š” ๋œป.
      • ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ์„ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์—ด์‡ 
    • ์ข…๋‹จ ์—ฐ์‚ฐ์ด ์—†๋Š” ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ์€ ์•„๋ฌด ์ผ๋„ ํ•˜์ง€ ์•Š๋Š” ๋ช…๋ น์–ด์ธ no-op๊ณผ ๊ฐ™์œผ๋‹ˆ, ์ข…๋‹จ ์—ฐ์‚ฐ์„ ๋นผ๋จน๋Š” ์ผ์ด ์ ˆ๋Œ€ ์—†๋„๋ก ํ•˜์ž.
    • ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ์€ ์ˆœ์ฐจ์ ์œผ๋กœ ์ˆ˜ํ–‰ ๋จ.
  • ์ŠคํŠธ๋ฆผ API์˜ ํŠน์ง•
    • ์ŠคํŠธ๋ฆผ API๋Š” ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ์ง€์›ํ•˜๋Š” ํ”Œ๋ฃจ์–ธํŠธ API(fluent API)์ž„
    • ์ŠคํŠธ๋ฆผ API๋Š” ๋‹ค์žฌ๋‹ค๋Šฅํ•˜์—ฌ ์‚ฌ์‹ค์ƒ ์–ด๋– ํ•œ ๊ณ„์‚ฐ์ด๋ผ๋„ ํ•ด๋‚ผ ์ˆ˜ ์žˆ์Œ.

2. ์ŠคํŠธ๋ฆผ์˜ ์‚ฌ์šฉ

  • ์ŠคํŠธ๋ฆผ์„ ์ ์ ˆํžˆ ํ™œ์šฉํ•ด ์•„๋‚˜๊ทธ๋žจ ๊ทธ๋ฃน์„ ์ถœ๋ ฅํ•˜๋Š” ์˜ˆ์‹œ
// ์ŠคํŠธ๋ฆผ์„ ์ ์ ˆํžˆ ํ™œ์šฉํ•˜๋ฉด ๊น”๋”ํ•˜๊ณ  ๋ช…๋ฃŒํ•ด์ง„๋‹ค.
public class HybridAnagrams {
    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(g -> System.out.println(g.size() + ": " + g));
        }
    }

    private static String alphabetize(String s) {
        char[] a = s.toCharArray();
        Arrays.sort(a);
        return new String(a);
    }
}
  • ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์ ์ ˆํ•œ ๊ฒฝ์šฐ
    • ์›์†Œ๋“ค์˜ ์‹œํ€€์Šค๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ๋ณ€ํ™˜ํ•œ๋‹ค.
    • ์›์†Œ๋“ค์˜ ์‹œํ€€์Šค๋ฅผ ํ•„ํ„ฐ๋งํ•œ๋‹ค.
    • ์›์†Œ๋“ค์˜ ์‹œํ€€์Šค๋ฅผ ํ•˜๋‚˜์˜ ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ•ด ๊ฒฐํ•ฉํ•œ๋‹ค(๋”ํ•˜๊ธฐ, ์—ฐ๊ฒฐํ•˜๊ธฐ, ์ตœ์†Ÿ๊ฐ’ ๊ตฌํ•˜๊ธฐ ๋“ฑ)
    • ์›์†Œ๋“ค์˜ ์‹œํ€€์Šค๋ฅผ ์ปฌ๋ ‰์…˜์— ๋ชจ์€๋‹ค(์•„๋งˆ๋„ ๊ณตํ†ต๋œ ์†์„ฑ์„ ๊ธฐ์ค€์œผ๋กœ ๋ฌถ์–ด๊ฐ€๋ฉฐ)
    • ์›์†Œ๋“ค์˜ ์‹œํ€€์Šค์—์„œ ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์›์†Œ๋ฅผ ์ฐพ๋Š”๋‹ค.
  • ์ŠคํŠธ๋ฆผ ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์ 
    • ์ŠคํŠธ๋ฆผ์„ ๊ณผ์šฉํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ฝ๊ฑฐ๋‚˜ ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง„๋‹ค.
    • char ๊ฐ’๋“ค์„ ์ฒ˜๋ฆฌํ•  ๋•Œ๋Š” ์ŠคํŠธ๋ฆผ์„ ์‚ผ๊ฐ€๋Š” ํŽธ์ด ๋‚ซ๋‹ค.
      • ์ž๋ฐ”๊ฐ€ ๊ธฐ๋ณธ ํƒ€์ž…์ธ char์šฉ ์ŠคํŠธ๋ฆผ์„ ์ง€์›ํ•˜์ง€ ์•Š์Œ.
      • CharSequence ์ธํ„ฐํŽ˜์ด์Šค์˜ chars() ๋ฉ”์„œ๋“œ๋Š” ๋ฐ˜ํ™˜ ๊ฐ’์ด IntStream ์ž„.
    • ๋ฐ˜๋ณต๋ฌธ์„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒŒ ๊ฐ€๋Šฅํ• ์ง€๋ผ๋„ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜ ์ธก๋ฉด์—์„œ๋Š” ์†ํ•ด๋ฅผ ๋ณผ ์ˆ˜๋„ ์žˆ์Œ
  • ๊ถŒ์žฅ
    • ์ŠคํŠธ๋ฆผ๊ณผ ๋ฐ˜๋ณต๋ฌธ์„ ์ ์ ˆํžˆ ์กฐํ•ฉํ•˜์ž
      • ํ•จ์ˆ˜ ๊ฐ์ฒด๋กœ๋Š” ํ•  ์ˆ˜ ์—†์ง€๋งŒ ๋ฐ˜๋ณต๋ฌธ(์ฝ”๋“œ ๋ธ”๋ก)์œผ๋กœ๋งŒ ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ๋“ค๋„ ์žˆ์Œ
        1. ๋ฒ”์œ„ ์•ˆ์˜ ์ง€์—ญ๋ณ€์ˆ˜ ์ฝ๊ธฐ / ์ˆ˜์ •. (๋žŒ๋‹ค์—์„œ๋Š” final์ด๊ฑฐ๋‚˜ ์‚ฌ์‹ค์ƒ final์ธ ๋ณ€์ˆ˜๋งŒ ์ฝ์„ ์ˆ˜ ์žˆ์Œ)
        2. return, break, continue๋ฌธ ์‚ฌ์šฉ. (๋žŒ๋‹ค์—์„œ๋Š” ๋ถˆ๊ฐ€๋Šฅ)
        3. ๋ฉ”์„œ๋“œ ์„ ์–ธ์— ๋ช…์‹œ๋œ ๊ฒ€์‚ฌ ์˜ˆ์™ธ ๋˜์ง€๊ธฐ. (๋žŒ๋‹ค์—์„œ๋Š” ๋ถˆ๊ฐ€๋Šฅ)
    • ๊ธฐ์กด ์ฝ”๋“œ๋Š” ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ฆฌํŒฉํ„ฐ๋งํ•˜๋˜, ์ƒˆ ์ฝ”๋“œ๊ฐ€ ๋” ๋‚˜์•„ ๋ณด์ผ ๋•Œ๋งŒ ๋ฐ˜์˜ํ•˜์ž
    • ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ ์ด๋ฆ„์€ ์›์†Œ์˜ ์ •์ฒด๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ๋ณต์ˆ˜๋ช…์‚ฌ๋กœ ์“ฐ๊ธฐ๋ฅผ ๊ฐ•๋ ฅํžˆ ์ถ”์ฒœ
      • ex) static Stream<BigInteger> primes() { ... }


๐Ÿ’ก ์ŠคํŠธ๋ฆผ์—์„œ๋Š” ๋ถ€์ž‘์šฉ ์—†๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

โ€œ์ŠคํŠธ๋ฆผ ์—ฐ์‚ฐ์— ๊ฑด๋„ค๋Š” ํ•จ์ˆ˜ ๊ฐ์ฒด๋Š” ๋ชจ๋‘ ๋ถ€์ž‘์šฉ(side effect)์ด ์—†์–ด์•ผ ํ•œ๋‹คโ€

1. ์ŠคํŠธ๋ฆผ ํŒจ๋Ÿฌ๋‹ค์ž„

  • ์ŠคํŠธ๋ฆผ ํŒจ๋Ÿฌ๋‹ค์ž„์˜ ํ•ต์‹ฌ์€ ๊ณ„์‚ฐ์„ ์ผ๋ จ์˜ ๋ณ€ํ™˜(transformation)์œผ๋กœ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ๋ถ€๋ถ„
  • ๊ฐ ๋ณ€ํ™˜ ๋‹จ๊ณ„๋Š” ๊ฐ€๋Šฅํ•œ ํ•œ ์ด์ „ ๋‹จ๊ณ„์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜์—ฌ์•ผ ํ•จ.
    • ์ˆœ์ˆ˜ ํ•จ์ˆ˜ : ๋‹ค๋ฅธ ๊ฐ€๋ณ€ ์ƒํƒœ๋ฅผ ์ฐธ์กฐํ•˜๊ฑฐ๋‚˜ ํ•จ์ˆ˜ ์Šค์Šค๋กœ ๋‹ค๋ฅธ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์œผ๋ฉฐ ์˜ค์ง ์ž…๋ ฅ๋งŒ์ด ๊ฒฐ๊ณผ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ํ•จ์ˆ˜
  • ์ŠคํŠธ๋ฆผ ์—ฐ์‚ฐ์— ๊ฑด๋„ค๋Š” ํ•จ์ˆ˜ ๊ฐ์ฒด๋Š” ๋ชจ๋‘ ๋ถ€์ž‘์šฉ(side effect)์ด ์—†์–ด์•ผ ํ•จ.

2. forEach ์ข…๋‹จ ์—ฐ์‚ฐ

  • forEach ์—ฐ์‚ฐ์€ ์ข…๋‹จ ์—ฐ์‚ฐ ์ค‘ ๊ธฐ๋Šฅ์ด ๊ฐ€์žฅ ์ ๊ณ  ๊ฐ€์žฅ โ€˜๋œโ€™ ์ŠคํŠธ๋ฆผ๋‹ค์›€.
  • ๋Œ€๋†“๊ณ  ๋ฐ˜๋ณต์ ์ด๋ผ์„œ ๋ณ‘๋ ฌํ™”ํ•  ์ˆ˜๋„ ์—†์Œ.

โ†’ forEach ์—ฐ์‚ฐ์€ ์ŠคํŠธ๋ฆผ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ•  ๋•Œ๋งŒ ์‚ฌ์šฉํ•˜๊ณ , ๊ณ„์‚ฐํ•˜๋Š” ๋ฐ๋Š” ์“ฐ์ง€ ๋ง์ž.


3. ์ˆ˜์ง‘๊ธฐ(collector)

  • ์ŠคํŠธ๋ฆผ์„ ์˜ฌ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ˆ˜์ง‘๊ธฐ๋ฅผ ์ž˜ ์•Œ์•„๋‘ฌ์•ผ ํ•จ.
  • ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ์ผ๋ฐ˜์ ์œผ๋กœ java.util.stream.Collectors ์˜ ๋ฉค๋ฒ„๋ฅผ ์ •์  ์ž„ํฌํŠธํ•˜์—ฌ ์‚ฌ์šฉํ•จ.
  • ์ˆ˜์ง‘๊ธฐ๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ๊ฐ์ฒด๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ปฌ๋ ‰์…˜์ž„.
  • ์ค‘์š”ํ•œ 5๊ฐ€์ง€ ์ˆ˜์ง‘๊ธฐ ํŒฉํ„ฐ๋ฆฌ๋ฅผ ์•Œ์•„๋ณด์ž
  1. toList() : ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
// ๋นˆ๋„ํ‘œ์—์„œ ๊ฐ€์žฅ ํ”ํ•œ ๋‹จ์–ด 10๊ฐœ๋ฅผ ๋ฝ‘์•„๋‚ด๋Š” ํŒŒ์ดํ”„๋ผ์ธ
List<String> topTen = freq.keySet().stream()
        .sorted(comparing(freq::get).reversed())
        .limit(10)
        .collect(toList());
  1. toMap(keyMapper, valueMapper) : ํ‚ค ๋งคํผ์™€ ๊ฐ’ ๋งคํผ๋ฅผ ๋ฐ›์•„ ๋งต์„ ๋ฐ˜ํ™˜
Map<String, Operation> stringToEnum =
		Stream.of(values()).collect(
				toMap(Object::toString, e -> e));
  1. toSet() : ์ง‘ํ•ฉ ๋ฐ˜ํ™˜
Set<String> result = givenList.stream()
  .collect(toSet());
  1. joining() : ์›์†Œ๋“ค์„ ์—ฐ๊ฒฐํ•˜์—ฌ ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜
// ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—†์„ ๊ฒฝ์šฐ : "abbcccdd" ์ถœ๋ ฅ
String result = givenList.stream()
  .collect(joining());

// ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ(๊ตฌ๋ถ„๋ฌธ์ž๋ฅผ ์—ฐ๊ฒฐ๋ถ€์œ„์— ์‚ฝ์ž…ํ•ด ์คŒ) : "a bb ccc dd" ์ถœ๋ ฅ
String result = givenList.stream()
  .collect(joining(" "));
  1. groupingBy(classifier) : ๋ถ„๋ฅ˜ ํ•จ์ˆ˜๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„ ์›์†Œ๋“ค์„ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„๋กœ ๋ชจ์•„ ๋†“์€ ๋งต์„ ๋‹ด์€ ์ˆ˜์ง‘๊ธฐ ๋ฐ˜ํ™˜.
// ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ : ์•ŒํŒŒ๋ฒณํ™”ํ•œ ๋‹จ์–ด๋ฅผ ์•ŒํŒŒ๋ฒณํ™” ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™์€ ๋‹จ์–ด๋“ค์˜ ๋ฆฌ์ŠคํŠธ๋กœ ๋งคํ•‘ํ•˜๋Š” ๋งต ์ƒ์„ฑ.
private static String alphabetize(String s) {
    char[] a = s.toCharArray();
    Arrays.sort(a);
    return new String(a);
}

words.collect(groupingBy(word -> alphabetize(word))); 

// ๋ถ„๋ฅ˜ ํ•จ์ˆ˜์™€ ๋‹ค์šด ์ŠคํŠธ๋ฆผ์„ ๋ฐ›๋Š” ์˜ˆ์‹œ
/** ๋‹ค์šด์ŠคํŠธ๋ฆผ ์ˆ˜์ง‘๊ธฐ๋กœ counting()์„ ๊ฑด๋„ค์„œ ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ(ํ‚ค)๋ฅผ (์›์†Œ๋ฅผ ๋‹ด์€ ์ปฌ๋ ‰์…˜์ด ์•„๋‹Œ)
	* ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ์— ์†ํ•˜๋Š” ์›์†Œ์˜ ๊ฐœ์ˆ˜(๊ฐ’)์™€ ๋งคํ•‘ํ•œ ๋งต์„ ์–ป์Œ
	*/
// ์ŠคํŠธ๋ฆผ์„ ์ œ๋Œ€๋กœ ํ™œ์šฉํ•ด ๋นˆ๋„ํ‘œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
Map<String, Long> freq;
try (Stream<String> words = new Scanner(file).tokens()) {
    freq = words
            .collect(groupingBy(String::toLowerCase, counting()));
}
  • [์ฐธ๊ณ ] groupingBy ๋ช…์„ธ
static <T,K> Collector<T,?,Map<K,List<T>>> 
  groupingBy(Function<? super T,? extends K> classifier)

static <T,K,A,D> Collector<T,?,Map<K,D>>
  groupingBy(Function<? super T,? extends K> classifier, 
    Collector<? super T,A,D> downstream)

static <T,K,D,A,M extends Map<K,D>> Collector<T,?,M>
  groupingBy(Function<? super T,? extends K> classifier, 
    Supplier<M> mapFactory, Collector<? super T,A,D> downstream)


๐Ÿ’ก ๋ฐ˜ํ™˜ ํƒ€์ž…์œผ๋กœ๋Š” ์ŠคํŠธ๋ฆผ๋ณด๋‹ค ์ปฌ๋ ‰์…˜์ด ๋‚ซ๋‹ค

โ€œ์›์†Œ ์‹œํ€€์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ณต๊ฐœ API์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์—๋Š” Collection์ด๋‚˜ ๊ทธ ํ•˜์œ„ ํƒ€์ž…์„ ์“ฐ๋Š” ๊ฒŒ ์ผ๋ฐ˜์ ์œผ๋กœ ์ตœ์„ โ€

1. ์ŠคํŠธ๋ฆผ ๋ฐ˜ํ™˜์˜ ๋ฌธ์ œ์ 

  • ์ŠคํŠธ๋ฆผ์€ ๋ฐ˜๋ณต(iteration)์„ ์ง€์›ํ•˜์ง€ ์•Š์Œ
  • API๋ฅผ ์ŠคํŠธ๋ฆผ๋งŒ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์งœ๋†“์œผ๋ฉด ๋ฐ˜ํ™˜๋œ ์ŠคํŠธ๋ฆผ์„ for-each๋กœ ๋ฐ˜๋ณตํ•˜๊ธธ ์›ํ•˜๋Š” ์‚ฌ์šฉ์ž๋Š” ๋ถˆ๋งŒ์„ ํ† ๋กœํ•  ๊ฒƒ์ž„.
  • Stream<E>๋ฅผ Iterable<E>๋กœ ์ค‘๊ฐœํ•ด์ฃผ๋Š” ์–ด๋Œ‘ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ŠคํŠธ๋ฆผ์„ for-each๋ฌธ์œผ๋กœ ๋ฐ˜๋ณตํ•  ์ˆ˜ ์žˆ์Œ
    • ๊ทธ๋Ÿฌ๋‚˜ ์–ด๋Œ‘ํ„ฐ๋Š” ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์–ด์ˆ˜์„ ํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ๋Š๋ฆผ.
// ์ŠคํŠธ๋ฆผ <-> ๋ฐ˜๋ณต์ž ์–ด๋Œ‘ํ„ฐ
public class Adapters {
    // Stream<E>๋ฅผ Iterable<E>๋กœ ์ค‘๊ฐœํ•ด์ฃผ๋Š” ์–ด๋Œ‘ํ„ฐ
    public static <E> Iterable<E> iterableOf(Stream<E> stream) {
        return stream::iterator;
    }

    // Iterable<E>๋ฅผ Stream<E>๋กœ ์ค‘๊ฐœํ•ด์ฃผ๋Š” ์–ด๋Œ‘ํ„ฐ
    public static <E> Stream<E> streamOf(Iterable<E> iterable) {
        return StreamSupport.stream(iterable.spliterator(), false);
    }
}

2. Collection ๋ฐ˜ํ™˜

  • Collection ์ธํ„ฐํŽ˜์ด์Šค๋Š” Iterable์˜ ํ•˜์œ„ ํƒ€์ž…์ด๊ณ  stream ๋ฉ”์„œ๋“œ๋„ ์ œ๊ณตํ•˜๋‹ˆ ๋ฐ˜๋ณต๊ณผ ์ŠคํŠธ๋ฆผ์„ ๋™์‹œ์— ์ง€์›ํ•จ.

โ†’ ์›์†Œ ์‹œํ€€์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ณต๊ฐœ API์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์—๋Š” Collection ์ด๋‚˜ ๊ทธ ํ•˜์œ„ ํƒ€์ž…์„ ์“ฐ๋Š” ๊ฒŒ ์ผ๋ฐ˜์ ์œผ๋กœ ์ตœ์„ ์ž„.

  • ๋ฐ˜ํ™˜ํ•˜๋Š” ์‹œํ€€์Šค์˜ ํฌ๊ธฐ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ ค๋„ ์•ˆ์ „ํ•  ๋งŒํผ ์ž‘์€ ๊ฒฝ์šฐ

โ†’ ArrayList๋‚˜ HashSet ๊ฐ™์€ ํ‘œ์ค€ ์ปฌ๋ ‰์…˜ ๊ตฌํ˜„์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ž

  • ๋ฐ˜ํ™˜ํ•˜๋Š” ์‹œํ€€์Šค์˜ ํฌ๊ธฐ๊ฐ€ ๋ฉ์น˜๊ฐ€ ํฐ ๊ฒฝ์šฐ

โ†’ ์ „์šฉ ์ปฌ๋ ‰์…˜์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ์•ˆ์„ ๊ฒ€ํ† ํ•ด๋ณด์ž.

  • ์ „์šฉ ์ปฌ๋ ‰์…˜ ๊ตฌํ˜„ ์˜ˆ์‹œ
public class PowerSet {
    // ์ž…๋ ฅ ์ง‘ํ•ฉ์˜ ๋ฉฑ์ง‘ํ•ฉ์„ ์ „์šฉ ์ปฌ๋ ‰์…˜์— ๋‹ด์•„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
    public static final <E> Collection<Set<E>> of(Set<E> s) {
        List<E> src = new ArrayList<>(s);
        if (src.size() > 30)
            throw new IllegalArgumentException(
                "์ง‘ํ•ฉ์— ์›์†Œ๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์Šต๋‹ˆ๋‹ค(์ตœ๋Œ€ 30๊ฐœ).: " + s);
        return new AbstractList<Set<E>>() {
            @Override public int size() {
                // ๋ฉฑ์ง‘ํ•ฉ์˜ ํฌ๊ธฐ๋Š” 2๋ฅผ ์›๋ž˜ ์ง‘ํ•ฉ์˜ ์›์†Œ ์ˆ˜๋งŒํผ ๊ฑฐ๋“ญ์ œ๊ณฑ ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.
                return 1 << src.size();
            }

            @Override public boolean contains(Object o) {
                return o instanceof Set && src.containsAll((Set)o);
            }

            @Override public Set<E> get(int index) {
                Set<E> result = new HashSet<>();
                for (int i = 0; index != 0; i++, index >>= 1)
                    if ((index & 1) == 1)
                        result.add(src.get(i));
                return result;
            }
        };
    }

    public static void main(String[] args) {
        Set s = new HashSet(Arrays.asList(args));
        System.out.println(PowerSet.of(s));
    }
}
  • (๋ฐ˜๋ณต์ด ์‹œ์ž‘๋˜๊ธฐ ์ „์—๋Š” ์‹œํ€€์Šค์˜ ๋‚ด์šฉ์„ ํ™•์ •ํ•  ์ˆ˜ ์—†๋Š” ๋“ฑ์˜ ์‚ฌ์œ ๋กœ) contains์™€ size๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒŒ ๋ถˆ๊ฐ€๋Šฅํ•  ๋•Œ(์ฆ‰, ์ปฌ๋ ‰์…˜์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒŒ ๋ถˆ๊ฐ€๋Šฅํ•  ๋•Œ)๋Š” ์ปฌ๋ ‰์…˜๋ณด๋‹ค๋Š” ์ŠคํŠธ๋ฆผ์ด๋‚˜ Iterable์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํŽธ์ด ๋‚ซ๋‹ค.


๐Ÿ’ก ์ŠคํŠธ๋ฆผ ๋ณ‘๋ ฌํ™”๋Š” ์ฃผ์˜ํ•ด์„œ ์ ์šฉํ•˜๋ผ

โ€œ๊ณ„์‚ฐ๋„ ์˜ฌ๋ฐ”๋กœ ์ˆ˜ํ–‰ํ•˜๊ณ  ์„ฑ๋Šฅ๋„ ๋นจ๋ผ์งˆ ๊ฑฐ๋ผ๋Š” ํ™•์‹  ์—†์ด๋Š” ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ ๋ณ‘๋ ฌํ™”๋Š” ์‹œ๋„์กฐ์ฐจ ํ•˜์ง€ ๋ง๋ผโ€

1. ์ŠคํŠธ๋ฆผ ๋ณ‘๋ ฌํ™”์˜ ๋ฌธ์ œ์ 

// ๋ณ‘๋ ฌ ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•ด ์ฒ˜์Œ 20๊ฐœ์˜ ๋ฉ”๋ฅด์„ผ ์†Œ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ
// ์ฃผ์˜: ๋ณ‘๋ ฌํ™”์˜ ์˜ํ–ฅ์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒํ•˜์ง€ ์•Š๋Š”๋‹ค.
public class ParallelMersennePrimes {
    public static void main(String[] args) {
        primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE))
                .parallel() // ์ŠคํŠธ๋ฆผ ๋ณ‘๋ ฌํ™”
                .filter(mersenne -> mersenne.isProbablePrime(50))
                .limit(20)
                .forEach(System.out::println);
    }

    static Stream<BigInteger> primes() {
        return Stream.iterate(TWO, BigInteger::nextProbablePrime);
    }
}
  • ์ด ํ”„๋กœ๊ทธ๋žจ์€ ์•„๋ฌด๊ฒƒ๋„ ์ถœ๋ ฅํ•˜์ง€ ๋ชปํ•˜๋ฉด์„œ CPU๋Š” 90%๋‚˜ ์žก์•„๋จน๋Š” ์ƒํƒœ๊ฐ€ ์ง€์†๋จ(์‘๋‹ต ๋ถˆ๊ฐ€; liveness failure)
  • ๋ฌด์Šจ ์ผ์ด ๋ฒŒ์–ด์ง„ ๊ฑธ๊นŒ?

โ†’ ์ŠคํŠธ๋ฆผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ด ํŒŒ์ดํ”„๋ผ์ธ์„ ๋ณ‘๋ ฌํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋‚ด์ง€ ๋ชปํ–ˆ๊ธฐ ๋•Œ๋ฌธ.

  • ๋ฐ์ดํ„ฐ ์†Œ์Šค๊ฐ€ Stream.iterate ๊ฑฐ๋‚˜ ์ค‘๊ฐ„ ์—ฐ์‚ฐ์œผ๋กœ limit๋ฅผ ์“ฐ๋ฉด ํŒŒ์ดํ”„๋ผ์ธ ๋ณ‘๋ ฌํ™”๋กœ๋Š” ์„ฑ๋Šฅ ๊ฐœ์„ ์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์—†์Œ.

โ†’ ์œ„ ์ฝ”๋“œ๋Š” ๋‘ ๋ฌธ์ œ๋ฅผ ๋ชจ๋‘ ์ง€๋‹ˆ๊ณ  ์žˆ์Œ..

  • ๊ตํ›ˆ : ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋งˆ๊ตฌ์žก์ด๋กœ ๋ณ‘๋ ฌํ™”ํ•˜๋ฉด ์•ˆ ๋จ. ์˜คํžˆ๋ ค ๋”์ฐํ•œ ์„ฑ๋Šฅ์ €ํ•˜๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ.
  • ์ŠคํŠธ๋ฆผ์„ ์ž˜๋ชป ๋ณ‘๋ ฌํ™”ํ•˜๋ฉด (์‘๋‹ต ๋ถˆ๊ฐ€๋ฅผ ํฌํ•จํ•ด) ์„ฑ๋Šฅ์ด ๋‚˜๋น ์งˆ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ฒฐ๊ณผ ์ž์ฒด๊ฐ€ ์ž˜๋ชป๋˜๊ฑฐ๋‚˜ ์˜ˆ์ƒ ๋ชปํ•œ ๋™์ž‘์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ.

โ†’ ์ŠคํŠธ๋ฆผ ๋ณ‘๋ ฌํ™”๋Š” ์˜ค์ง ์„ฑ๋Šฅ ์ตœ์ ํ™” ์ˆ˜๋‹จ์ž„์„ ๊ธฐ์–ตํ•˜์ž. ๋ฐ˜๋“œ์‹œ ๋ณ€๊ฒฝ ์ „ํ›„๋กœ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜์—ฌ ๋ณ‘๋ ฌํ™”๋ฅผ ์‚ฌ์šฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š”์ง€ ๋”ฐ์ ธ๋ณด์ž.


2. ์ŠคํŠธ๋ฆผ ๋ณ‘๋ ฌํ™”๊ฐ€ ์ ํ•ฉํ•œ ๊ฒฝ์šฐ

  • ์ŠคํŠธ๋ฆผ์˜ ์†Œ์Šค๊ฐ€ ArrayList, HashMap, HashSet, ConcurrentHashMap ์˜ ์ธ์Šคํ„ด์Šค๊ฑฐ๋‚˜ ๋ฐฐ์—ด, int ๋ฒ”์œ„, long ๋ฒ”์œ„์ผ ๋•Œ ์ ํ•ฉ.
  • ์œ„ ์ž๋ฃŒ๊ตฌ์กฐ๋“ค์˜ ํŠน์ง•
    1. ๋ฐ์ดํ„ฐ๋ฅผ ์›ํ•˜๋Š” ํฌ๊ธฐ๋กœ ์ •ํ™•ํ•˜๊ณ  ์†์‰ฝ๊ฒŒ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์–ด์„œ ์ผ์„ ๋‹ค์ˆ˜์˜ ์Šค๋ ˆ๋“œ์— ๋ถ„๋ฐฐํ•˜๊ธฐ์— ์ข‹์Œ
    2. ์ฐธ์กฐ ์ง€์—ญ์„ฑ(locality of reference)์ด ๋›ฐ์–ด๋‚จ
      • ์ด์›ƒํ•œ ์›์†Œ์˜ ์ฐธ์กฐ๋“ค์ด ๋ฉ”๋ชจ๋ฆฌ์— ์—ฐ์†ํ•ด์„œ ์ €์žฅ๋˜์–ด ์žˆ๋‹ค๋Š” ๋œป
      • ์ฐธ์กฐ ์ง€์—ญ์„ฑ์€ ๋‹ค๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฒŒํฌ ์—ฐ์‚ฐ์„ ๋ณ‘๋ ฌํ™”ํ•  ๋•Œ ์•„์ฃผ ์ค‘์š”ํ•œ ์š”์†Œ
  • ์ข…๋‹จ ์—ฐ์‚ฐ ์ค‘์—๋Š” ์ถ•์†Œ(reduction)๊ฐ€ ๋ณ‘๋ ฌํ™”์— ๊ฐ€์žฅ ์ ํ•ฉ.
    • ์ถ•์†Œ : ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ๋งŒ๋“ค์–ด์ง„ ์›์†Œ๋ฅผ ํ•˜๋‚˜๋กœ ํ•ฉ์น˜๋Š” ์ž‘์—…
    • ex) Stream์˜ reduce๋ฉ”์„œ๋“œ ์ค‘ ํ•˜๋‚˜, ํ˜น์€ min, max, count, sum ๋“ฑ
  • ์กฐ๊ฑด์— ๋งž์œผ๋ฉด ๋ฐ”๋กœ ๋ฐ˜ํ™˜๋˜๋Š” ๋ฉ”์„œ๋“œ๋„ ๋ณ‘๋ ฌํ™”์— ์ ํ•ฉ
    • ex) anyMatch, allMatch, noneMatch ๋“ฑ
  • ์ŠคํŠธ๋ฆผ ๋ณ‘๋ ฌํ™”์˜ ์ ํ•ฉํ•œ ์˜ˆ์‹œ
public class ParallelPrimeCounting {
    // ์†Œ์ˆ˜ ๊ณ„์‚ฐ ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ - ๋ณ‘๋ ฌํ™” ๋ฒ„์ „
    static long pi(long n) {
        return LongStream.rangeClosed(2, n)
                .parallel()
                .mapToObj(BigInteger::valueOf)
                .filter(i -> i.isProbablePrime(50))
                .count();
    }

    public static void main(String[] args) {
        System.out.println(pi(10_000_000));
    }
}

์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ