DevLog ๐Ÿ˜ถ

[๋ชจ๋˜์ž๋ฐ”์ธ์•ก์…˜] ๋žŒ๋‹ค ํ‘œํ˜„์‹ : ์ต๋ช… ํ•จ์ˆ˜๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ๋ณธ๋ฌธ

๐Ÿ“–/Modern Java in Action

[๋ชจ๋˜์ž๋ฐ”์ธ์•ก์…˜] ๋žŒ๋‹ค ํ‘œํ˜„์‹ : ์ต๋ช… ํ•จ์ˆ˜๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ

dolmeng2 2023. 2. 27. 18:53

๐Ÿ’ฌ ๋ชจ๋˜ ์ž๋ฐ” ์ธ ์•ก์…˜ ์ฑ•ํ„ฐ 3์„ ์ฝ๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค. 

 


โœ”๏ธ ๋žŒ๋‹ค๊ฐ€ ๋ญ”๋ฐ์š”?

์ง€๋‚œ ์ฑ•ํ„ฐ์—์„œ๋Š” ๋™์ž‘ ํŒŒ๋ผ๋ฏธํ„ฐํ™”๋ฅผ ํ†ตํ•ด์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฉ”์„œ๋“œ์˜ ๋™์ž‘ ์ž์ฒด๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๋Š” ๊ฒƒ์„ ๋ฐฐ์› ๋‹ค. ์ด๋•Œ, ๋ฉ”์„œ๋“œ์˜ ๋™์ž‘์„ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ณ„๋„์˜ @Override ์–ด๋…ธํ…Œ์ด์…˜์ด๋‚˜ ์ƒ์†๋œ ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ๋“ฑ, ๋™์ž‘ ์™ธ์— ๋‹ค๋ฅธ ์ฝ”๋“œ๋“ค์ด ๋ฐ˜๋ณต๋˜์–ด ์ƒ๋‹นํžˆ ๋ถˆํŽธํ–ˆ๋‹ค. ๋žŒ๋‹ค ํ‘œํ˜„์‹์€ ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ, ๋‹จ์ˆœํžˆ '๋™์ž‘์— ๋Œ€ํ•œ ์ฝ”๋“œ๋งŒ' ๋ฉ”์„œ๋“œ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ต๋ช… ํ•จ์ˆ˜๋ฅผ ๋‹จ์ˆœํ™”ํ•œ ๊ฒƒ์ด๋‹ค.

 

๋žŒ๋‹ค ํ‘œํ˜„์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์ง•์„ ๊ฐ€์ง„๋‹ค.

๐Ÿ’ฌ ๋ฉ”์„œ๋“œ์— ์ด๋ฆ„์ด ์—†์œผ๋‹ˆ๊นŒ “์ต๋ช…”์ด๋‹ค. (๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ๋„ค์ด๋ฐ์„ ๊ณ ๋ฏผํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค!)
- ์ด๋ฆ„์€ ์—†์ง€๋งŒ, ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฆฌ์ŠคํŠธ์™€ ๋ฐ”๋””, ๋ฐ˜ํ™˜ ํ˜•์‹, ๋ฐœ์ƒ ๊ฐ€๋Šฅํ•œ ์˜ˆ์™ธ ๋ฆฌ์ŠคํŠธ๋Š” ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.
๐Ÿ’ฌ ํ•จ์ˆ˜ : ํŠน์ • ํด๋ž˜์Šค์— ์ข…์†๋˜์ง€ ์•Š๊ณ , ๋…๋ฆฝ์ ์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. ํ•˜์ง€๋งŒ ๋ฉ”์„œ๋“œ์ฒ˜๋Ÿผ ํŒŒ๋ผ๋ฏธํ„ฐ, ๋ฐ”๋””, ๋ฆฌํ„ด๊ฐ’, ๊ฐ€๋Šฅํ•œ ์˜ˆ์™ธ๊นŒ์ง€ ๋ชจ๋‘ ํฌํ•จํ•œ๋‹ค!
- ์ฑ•ํ„ฐ 1์—์„œ ์„ค๋ช…ํ–ˆ๋˜ (๋ฉ”์„œ๋“œ vs ํ•จ์ˆ˜์˜ ๋‚ด์šฉ์„ ์ƒ๊ฐํ•˜์ž!)
๐Ÿ’ฌ ์ „๋‹ฌ : ๋žŒ๋‹ค ํ‘œํ˜„์‹์€ ๋งˆ์น˜ ‘์ผ๊ธ‰ ๊ฐ์ฒด’์ฒ˜๋Ÿผ ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜, ๋ณ€์ˆ˜๋กœ ์ €์žฅ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
๐Ÿ’ฌ ๊ฐ„๊ฒฐ์„ฑ : ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•ด์ง„๋‹ค! ๋‹จ์ˆœํžˆ ๋™์ž‘ ์ž์ฒด๋งŒ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋‹ค.

 ๋žŒ๋‹ค ํ‘œํ˜„์‹์€ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์„๊นŒ?

(Crew a1, Crew a2) -> Integer.compare(a1.getAge(), a2.getAge());

 

(Crew a1, Crew a2) : ๋žŒ๋‹ค ํŒŒ๋ผ๋ฏธํ„ฐ, ํ˜„์žฌ ์ฝ”๋“œ์—์„œ๋Š” compareTo์— ์‚ฌ์šฉ๋˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ 2๊ฐœ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

→ : ํ™”์‚ดํ‘œ, ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฆฌ์ŠคํŠธ์™€ ๋ฐ”๋””๋ฅผ ๊ตฌ๋ถ„ํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

Integer.compare(a1.getAge(), a2.getAge()) : ๋žŒ๋‹ค ๋ฐ”๋””, ๋žŒ๋‹ค์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ํ‘œํ˜„ํ•ด์ค€๋‹ค.

 

๋˜ํ•œ, ๋žŒ๋‹ค๋Š” ํฌ๊ฒŒ ํ‘œํ˜„์‹ ์Šคํƒ€์ผ๊ณผ ๋ธ”๋ก ์Šคํƒ€์ผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ‘œํ˜„์‹ ์Šคํƒ€์ผ: () -> "Hello Crew!”

๋ธ”๋ก ์Šคํƒ€์ผ: () → { return “Hello Crew!”; }

 

๋ธ”๋ก์—์„œ๋Š” return๊ณผ ์„ธ๋ฏธ์ฝœ๋ก ์„ ๋ถ™์—ฌ์ค˜์•ผ ํ•œ๋‹ค. ์ฃผ๋กœ ์—ฌ๋Ÿฌ ํ–‰์„ ์ž…๋ ฅํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋ฉฐ, ๊ฐ„๊ฒฐํ•œ ๊ฒฝ์šฐ ํ‘œํ˜„์‹ ์Šคํƒ€์ผ๋กœ๋„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 


โœ”๏ธ ๊ทธ๋ž˜์„œ ๋žŒ๋‹ค… ์–ด๋””์„œ ์‚ฌ์šฉํ•˜๋Š”๋ฐ?

๋žŒ๋‹ค๋กœ ๊ฐ„๊ฒฐํ•ด์ง„๋‹ค๋Š” ๊ฒƒ๊นŒ์ง€๋Š” ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค. ํ•˜์ง€๋งŒ, ์ด๋ฅผ ์–ด๋–ป๊ฒŒ ์‘์šฉํ•˜๋ฉด ์ข‹์„์ง€ ์•„์ง ๊ฐ์ด ์žกํžˆ์ง€ ์•Š๋Š”๋‹ค. ๊ต์žฌ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋žŒ๋‹ค์˜ ์‚ฌ์šฉ๋ฒ•์„ ์„ค๋ช…ํ•œ๋‹ค. 

 

๐Ÿ’ก ์ฃผ๋กœ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

๊ฐ‘์ž๊ธฐ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค? ๋ฌด์Šจ ๋ง์ธ์ง€ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์ง€๋งŒ, ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ณธ ์ ์ด ์žˆ๋‹ค. ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋Š” '๋””ํดํŠธ ๋ฉ”์„œ๋“œ์˜ ์œ ๋ฌด์— ๊ด€๊ณ„์—†์ด, ์˜ค์ง ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ 1๊ฐœ๋งŒ ๊ฐ€์ง€๋Š” ์ธํ„ฐํŽ˜์ด์Šค'์ด๋‹ค. ์•„๋ž˜๋Š” ์ž๋ฐ”์—์„œ ์ œ๊ณตํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ์ค‘ ํ•˜๋‚˜์ธ Predicate์ด๋‹ค.

@FunctionalInterface
public interface Predicate<T> {
        boolean test(T t);
        }

์šฐ๋ฆฌ๋Š” ์ฑ•ํ„ฐ 2์—์„œ ์‚ฌ์šฉํ•˜์˜€๋˜ ๋‹ค์ค‘ ์กฐ๊ฑด์— ๋Œ€ํ•ด ๊ฒ€์ฆ์„ ์œ„ํ•ด Predicate ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค. ์—ฌ๊ธฐ์„œ Predicate<T>๋ฅผ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์˜ค์ง ํ•˜๋‚˜์˜ ์ถ”์ƒ ๋ฉ”์„œ๋“œ์ธ 'test()'๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

 

์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ ์ •๋ ฌํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” Comparator<T> ์—ญ์‹œ, ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ผ์ข…์ด๋‹ค.

@FunctionalInterface
public interface Comparator<T> {
        int compare(T o1, T o2);
        }

compare()๋ผ๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ์ž๋ฐ”์—์„œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์ž„์„ ์•Œ๋ฆฌ๊ธฐ ์œ„ํ•ด์„œ @FunctionalInterface๋ผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์„œ ํ‘œํ˜„ํ•œ๋‹ค. (ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ด๋ฉด ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์ž„์„ ๋ณด์žฅํ•˜๋ฉฐ, ์ถ”์ƒ ๋ฉ”์„œ๋“œ๊ฐ€ ์—†์–ด์ง€๊ฑฐ๋‚˜ ๋Š˜์–ด๋‚ฌ๋‹ค๋“ ์ง€, ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ •์˜์— ๋งž์ง€ ์•Š๊ฒŒ ๋˜๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.)

 

๐Ÿ’ฌ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋Š”?

์ถ”์ƒ ๋ฉ”์„œ๋“œ์˜ ์ •์˜์— ๋Œ€ํ•ด์„œ ํ—ท๊ฐˆ๋ฆด ์ˆ˜๋„ ์žˆ๋‹ค. ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ž€, ์ž์‹ ํด๋ž˜์Šค์—์„œ ๋ฐ˜๋“œ์‹œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•ด์•ผ์ง€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์ฆ‰, Comparator๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋Š” ๋ฐ˜๋“œ์‹œ compare()๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

NaturalOrderComparator implements Comparator<Comparable<Object>> {
@Override
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
        return c1.compareTo(c2);
        }

Intellij์˜ ๋„์›€์„ ๋ฐ›์•„, Comparator๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ๊ตฌํ˜„ํ•œ Comparators์˜ ๊ตฌํ˜„์ฒด์ธ NaturalOrderComparator๋ฅผ ๊ฐ€์ ธ์™”๋‹ค. (๋ณดํ†ต ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•  ๋•Œ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.) ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ๋ณด๋ฉด ์œ„์™€ ๊ฐ™์ด compare๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

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

 private static class ReverseComparator implements Comparator<Comparable<Object>>, Serializable {
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
        return c2.compareTo(c1);
        }

์˜ˆ๋ฅผ ๋“ค์–ด, NaturalOrderComparator์˜ ๊ฒฝ์šฐ ์œ„์™€ ๊ฐ™์ด ์ธ์ž๋กœ ๋“ค์–ด์˜จ c1, c2 ์ˆœ์œผ๋กœ ๋‘ ๊ฐ’์„ ๋น„๊ตํ•˜์ง€๋งŒ, ReverseComparator์˜ ๊ฒฝ์šฐ c2, c1 ์ˆœ์œผ๋กœ ๊ฐ’์„ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. 

 

์ž, ๋‹ค์‹œ ๋Œ์•„์™€์„œ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋Š” abstract ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋ฉฐ, ๋์— ์„ธ๋ฏธ์ฝœ๋ก (;)์„ ๋ถ™์ด๋Š” ๊ฒƒ์ด ๊ด€์Šต์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ธํ„ฐํŽ˜์ด์Šค์—์„œ๋Š” abstract๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๋Š” ‘์ถ”์ƒ ๋ฉ”์„œ๋“œ’๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

 

๊ทธ๋Ÿฌ๋ฉด, ์—ฌ๊ธฐ์„œ ํ€ด์ฆˆ! Child ์ธํ„ฐํŽ˜์ด์Šค๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

public interface Parent {
    int hello(int a, int b);
}
public interface Child extends Parent{
    int hello(double a, double b);
}

 

→ ๋•ก! Child ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†๋ฐ›์œผ๋ฉฐ ๋ฐ›์€ hello(int a, int b);์— ์˜ํ•ด์„œ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๊ฐ€ 2๊ฐœ๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ผ๊ณ  ํ•  ์ˆ˜ ์—†๋‹ค.


โœ”๏ธ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค… ์™œ ์“ฐ๋Š” ๊ฑด๋ฐ?

์•ž์„œ ๊ณ„์† ๋งํ•œ 'ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค'๋ผ๋Š” ๋‹จ์–ด๋กœ ์ธํ•ด์„œ ์Šฌ์Šฌ ์–ด์ง€๋Ÿฌ์›Œ์ง€๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค. ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋Š”, “์ถ”์ƒ ๋ฉ”์„œ๋“œ๊ฐ€ 1๊ฐœ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค”์ด๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด ๋ฌธ์žฅ์—์„œ “์ถ”์ƒ ๋ฉ”์„œ๋“œ๊ฐ€ 1๊ฐœ”๋ผ๋Š” ๊ฒƒ์— ์ฃผ๋ชฉํ•ด์•ผ ํ•œ๋‹ค. ๋žŒ๋‹ค ํ‘œํ˜„์‹์„ ํ†ตํ•ด, ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค!

 

๊ฐ„๋‹จํ•˜๊ฒŒ Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž. 

// ์ต๋ช… ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๊ฒฝ์šฐ
Runnable r1 = new Runnable() {
@Override
public void run() {
        System.out.println("Anonymous class");
        }
        };

// ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๊ฒฝ์šฐ
        Runnable r2 = () -> System.out.println("Lambda");

Runnable<T>์€ run()์ด๋ผ๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ 1๊ฐœ๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค. ์ต๋ช… ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด, ์œ„์™€ ๊ฐ™์ด Runnable ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•œ ๊ตฌํ˜„์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ํŒŒ๋ผ๋ฏธํ„ฐ ๋‚ด์—์„œ ๋ฐ”๋กœ ์ „๋‹ฌํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ, ๋‚ด๋ถ€์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ๋”ฑ 1๊ฐœ์ž„์„ ๋ณด์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•ด์„œ '๋™์ž‘ ์ž์ฒด'๋งŒ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค! ๐Ÿ‘

 

์ด๋•Œ, ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ๋žŒ๋‹ค ํ‘œํ˜„์‹์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ 'ํ•จ์ˆ˜ ๋””์Šคํฌ๋ฆฝํ„ฐ'๋ผ๋Š” ๋ณ„๋„์˜ ์šฉ์–ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์•ž์„œ ๋งํ•œ ๊ฒƒ์ฒ˜๋Ÿผ, ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋Š” ๋žŒ๋‹ค ํ‘œํ˜„์‹์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ’ก ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” ๋žŒ๋‹ค ํ‘œํ˜„์‹์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ๋™์ผํ•˜๋‹ค.
์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ์‹œ๊ทธ๋‹ˆ์ฒ˜์— ๋Œ€ํ•ด์„œ 'ํ•จ์ˆ˜ ๋””์Šคํฌ๋ฆฝํ„ฐ'๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์—ฌ๊ธฐ์„œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ž€, ๋ฉ”์„œ๋“œ๋ช…๊ณผ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ์ˆœ์„œ, ํƒ€์ž…, ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค. (๋ฆฌํ„ด ํƒ€์ž…, ์˜ˆ์™ธ๋Š” ์ œ์™ธํ•œ๋‹ค!)

// ๋žŒ๋‹ค ํ‘œํ˜„์‹ : () -> {}
// ์ด๋•Œ, ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” () -> void
execute(() -> {});

public void execute(Runnable r) {
        // ์ถ”์ƒ ๋ฉ”์„œ๋“œ
        // ์ด๋•Œ, ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” () -> void
        r.run();
        }

์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž. ์œ„ ์ฝ”๋“œ์—์„œ ๋žŒ๋‹ค ํ‘œํ˜„์‹์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” () -> void, ์ถ”์ƒ ๋ฉ”์„œ๋“œ์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์—ญ์‹œ () -> void์ด๋‹ค.  


โœ”๏ธ ์‹คํ–‰ ์–ด๋ผ์šด๋“œ ํŒจํ„ด

์ž๋ฐ”7์—์„œ๋ถ€ํ„ฐ ์ถ”๊ฐ€๋œ Try-with-resources๋ฅผ ํ™œ์šฉํ•˜๋ฉด try์— ์ž์› ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๊ณ , try ์ฝ”๋“œ ๋ธ”๋ก์ด ๋๋‚˜๋ฉด ์ž๋™์œผ๋กœ ์ž์›์„ ์ข…๋ฃŒํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ๋ชจ๋“  catch ๋ธ”๋ก์— ๋ณ„๋„์˜ ์ข…๋ฃŒ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ฑฐ๋‚˜, finally ๋ธ”๋ก์„ ์„ ์–ธํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค. ์ด์ „๊นŒ์ง€๋Š” ํ•ญ์ƒ ์ž์›์„ ์ƒ์„ฑํ•˜๊ณ , ์‚ฌ์šฉํ•˜๊ณ , ํ•ด์ œํ•  ๋•Œ์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์ค‘๋ณต๋˜๋Š” ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ–ˆ์—ˆ๋‹ค.

Resource resource = null;
        try {
        resource = getResource();
        // ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ ๋กœ์ง
        } catch (...) {
        ... // ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋กœ์ง
        } finally {
        if (resource != null) {
        try {
        resource.close(); // ์ž์› ํ• ๋‹น ํ•ด์ œ
        } catch (Exception ignored) {
        }
        }
        }

์ž์› ํ•ด์ œ๋ฅผ ์œ„ํ•ด์„œ, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ค‘๋ณต๋˜๋Š” try-catch ๋ฌธ์ด ํ•„์š”ํ–ˆ๋˜ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ์ž๋ฐ” 7์—์„œ๋Š” try-with-resources๋ผ๋Š” ํŠน์ง•์ด ์ถ”๊ฐ€๋˜์–ด, try์— ์ž์›์„ ์ „๋‹ฌํ•˜๊ฒŒ ๋˜๋ฉด finally์—์„œ ์ข…๋ฃŒ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š์•„๋„ ์ž๋™์œผ๋กœ ์ž์›์„ ์ข…๋ฃŒํ•ด์ฃผ๊ฒŒ ๋œ ๊ฒƒ์ด๋‹ค. 

try (Resource resource = getResource()) {
        // ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ
        } catch(...) {
        ...
        }

์œ„์™€ ๊ฐ™์ด ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•ด์ง€๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

์šฐ๋ฆฌ๋Š” ์œ„์™€ ๊ฐ™์€ ๊ณผ์ •์„ ์ด์ œ '์‹คํ–‰ ์–ด๋ผ์šด๋“œ ํŒจํ„ด'์ด๋ผ๊ณ  ๋งํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ , ์ด๋Ÿฌํ•œ ์‹คํ–‰ ์–ด๋ผ์šด๋“œ ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋žŒ๋‹ค์™€ ๋™์ž‘ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค. ๋ฒŒ์จ๋ถ€ํ„ฐ ๋ง์ด ๋„ˆ๋ฌด ์–ด๋ ต๋‹ค. ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•˜๋ฉด, ์‹ค์ œ ์ž์›์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋กœ์ง์„, ์„ค์ • + ์ •๋ฆฌ ๊ณผ์ •์œผ๋กœ ๊ฐ์‹ธ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

 

๐Ÿ’ก ์ฆ‰, ์‹คํ–‰ ์–ด๋ผ์šด๋“œ ํŒจํ„ด์ด๋ž€ (์ดˆ๊ธฐํ™”/์ค€๋น„) → ์ž‘์—… ์ฒ˜๋ฆฌ! → (์ •๋ฆฌ/๋งˆ๋ฌด๋ฆฌ) ์ด๋‹ค.

 

์‹ค์ œ๋กœ ์–ด๋–ค ์‹์œผ๋กœ ์‹คํ–‰ ์–ด๋ผ์šด๋“œ ํŒจํ„ด์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ ์‚ดํŽด๋ณด์ž.

public String processFile() throws IOException {
        try (BufferedReader br =
        new BufferedReader(new FileReader("data.txt"))) {
        return br.readLine();
        }
        }

BufferedReader๋ฅผ ํ†ตํ•ด ํŒŒ์ผ์˜ ํ•œ ์ค„์„ ์ฝ๋Š” ์ฝ”๋“œ์ด๋‹ค. ์œ„ ์ฝ”๋“œ๋ฅผ ์ฐจ๋ก€๋Œ€๋กœ ๋ณ€ํ™”์‹œ์ผœ๊ฐ€๋ฉฐ ์•Œ์•„๋ณด์ž.

 

๐Ÿ’ฌ ์ง€๊ธˆ์€ ๊ณ ์ž‘ ํ•œ ์ค„ ์ฝ๊ณ  ๋๋‚ด๋Š”๋ฐ, ๋‚˜๋Š” ํ•œ ๋ฒˆ์— 10์ค„์„ ์ฝ๋Š” ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด ์ฃผ์„ธ์š”.

: ์šฐ๋ฆฌ๊ฐ€ ์ด๋Ÿฌํ•œ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋ฐ›์•˜์„ ๋•Œ ๊ธฐ์กด์˜ ์ฝ”๋“œ์—์„œ ์–ด๋–ค ๊ฑธ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์„๊นŒ?

 

1. ์ด๋ฏธ ํŒŒ์ผ์— ์ ‘๊ทผํ•˜๋Š” ๋ถ€๋ถ„์€ ์žˆ๋‹ค.

2. ๊ฐ’์„ ์ฝ์–ด์˜ค๊ธฐ ์œ„ํ•œ Reader๋„ ์ค€๋น„๋˜์–ด ์žˆ๋‹ค.

3) 1์ค„์ด ์•„๋‹Œ, 10์ค„์„ ์ฝ๋„๋ก ํ•˜๋Š” ๋กœ์ง์ด ํ•„์š”ํ•˜๋‹ค.

 

์šฐ๋ฆฌ๋Š”, BufferedReader๋ฅผ ํ†ตํ•ด 10์ค„์„ ์ฝ๋„๋ก ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด, processFile() ๋ฉ”์„œ๋“œ์—๊ฒŒ ๋™์ž‘์„ ์ „๋‹ฌํ•ด์ฃผ๋„๋ก ์ˆ˜์ •ํ•  ๊ฒƒ์ด๋‹ค. ๋™์ž‘์„ ์ „๋‹ฌํ•ด์ฃผ๋Š” ๊ฒƒ, ์ฆ‰ ‘๋™์ž‘ ํŒŒ๋ผ๋ฏธํ„ฐํ™”’๋ฅผ ์ด์šฉํ•˜์ž๋Š” ๊ฒƒ์ด๋‹ค. 

// ์šฐ๋ฆฌ๋Š” ์ด๋ ‡๊ฒŒ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค.
String result =
        processFile((BufferedReader br) -> {
        StringBuilder fileMessage = new StringBuilder();
        for (int i = 0; i < 10; i++) {
        fileMessage.append(br.readLine());
        }
        return fileMessage.toString();
        };

์šฐ๋ฆฌ๋Š” ๋žŒ๋‹ค๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด 10์ค„์„ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค. (์ฒ˜์Œ๋ถ€ํ„ฐ ๋žŒ๋‹ค ํ‘œํ˜„์‹์„ ๋งŒ๋“ค์—ˆ๋‹ค๊ธฐ๋ณด๋‹จ, 10์ค„์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋™์ž‘ ์ž์ฒด๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒผ๋‹ค๊ณ  ๋ณด๋Š” ๊ฒƒ์ด ๋” ์‰ฝ๋‹ค.) processFile()์˜ ์ธ์ž๋กœ 10์ค„์„ ์ฝ๋Š” ๋™์ž‘ ์ž์ฒด๋ฅผ ์ „๋‹ฌํ•ด์ค€ ๊ฒƒ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ๋งŒ๋“  ๋™์ž‘ ์ž์ฒด๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐํ™” ์‹œ์ผฐ๋‹ค๋ฉด, ์ด์ œ ์ด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ•˜๋‚˜ ์„ ์–ธํ•ด๋ณด์ž.

 

@FunctionalInterface
public interface BufferedReaderProcessor {
    String process(BufferedReader b) throws IOException;
}

๋žŒ๋‹ค ํ‘œํ˜„์‹์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ์ถ”์ƒ ๋ฉ”์„œ๋“œ์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ BufferedReader๋ฅผ ์„ ์–ธํ•ด์ค€๋‹ค. (๋ฉ”์„œ๋“œ๋ช…์€ ์ต๋ช… ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„๋กœ ๊ณ ๋ คํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.) ์ด์ œ, ์ด๋Ÿฌํ•œ process() ๋ฉ”์„œ๋“œ์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ๋™์ผํ•œ ๋žŒ๋‹ค๋ฅผ ์ „๋‹ฌํ•ด๋ณด์ž.

 

public String processFile(BufferedReaderProcessor p) throws IOException {
        try (BufferedReader br =
        new BufferedReader(new FileReader("data.txt"))) {
        return p.process(br); // ์ด๋ ‡๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค!
        }
        }

์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, ์ธ์ž๋กœ BufferedReaderProcessor๋ผ๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ฐ›๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋ฐ›์€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ process() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์‹ค์ œ ๋™์ž‘์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค. ์ด์ œ, ์šฐ๋ฆฌ๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋‹ค์‹œ ํ•œ ๋ฒˆ  ๋™์ผํ•œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๊ฐ€์ง„ ๋žŒ๋‹ค ํ‘œํ˜„์‹์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

 

// 10์ค„ ์ฝ๊ธฐ
String tenLine =
        processFile((BufferedReader br) -> {
        StringBuilder fileMessage = new StringBuilder();
        for (int i = 0; i < 10; i++) {
        fileMessage.append(br.readLine());
        }
        return fileMessage.toString();
        };

// 1์ค„ ์ฝ๊ธฐ
        String oneLine =
        processFile((BufferedReader br) -> br.readLine());

์ตœ์ข…์ ์œผ๋กœ ์ •๋ฆฌํ•œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, ๋™์ž‘ ์ž์ฒด๋ฅผ ๋žŒ๋‹ค ํ‘œํ˜„์‹์œผ๋กœ ์ „๋‹ฌํ•˜์—ฌ 10์ค„๋กœ ์ฝ๋“ , 1์ค„๋กœ ์ฝ๋“  ์ž์œ ๋กญ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค. ์‹คํ–‰ ์–ด๋ผ์šด๋“œ ํŒจํ„ด์„ ํ™œ์šฉํ•˜์—ฌ, ์‹ค์ œ๋กœ ๋™์ž‘์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ, ๋žŒ๋‹ค ํ‘œํ˜„์‹์„ ํ™œ์šฉํ•ด ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋Š”, ์–ด๋–ค ๊ณผ์ •์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š”์ง€ ์ •๋ฆฌํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค. 

// Step 1 - return์—์„œ ๋ฐ”๋กœ ๋กœ์ง์„ ์„ ์–ธํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ™•์žฅ์„ฑ์ด ์—†๋‹ค.
public String processFile() throws IOException {
        try (BufferedReader br =
        new BufferedReader(new FileReader("data.txt"))) {
        return br.readLine();
        }
        }

// Step 2 - ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ์„ ์–ธํ•˜๊ธฐ
@FunctionalInterface
public interface BufferedReaderProcessor {
    String process(BufferedReader b) throws IOException;
}

    // ๊ธฐ์กด์˜ ์ฝ”๋“œ์—์„œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๋งž์ถฐ์ค€๋‹ค.
    public String processFile(BufferedReaderProcessor p) throws IOException { 
	...
    }

    // step 3 - ๋‚ด๋ถ€ ๊ตฌํ˜„ ๋กœ์ง์„ ๊ฐˆ์•„๋ผ์šธ ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค๊ธฐ.
    public String processFile(BufferedReaderProcessor p) throws IOException {
        try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
            return p.process(br);
        }
    }

    // step 4 - ๋žŒ๋‹ค๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ!
    String tenLine =
            processFile((BufferedReader br) -> {
        StringBuilder fileMessage = new StringBuilder();
        for (int i = 0; i < 10; i++) {
        fileMessage.append(br.readLine());
        }
        return fileMessage.toString();
        };

// 1์ค„ ์ฝ๊ธฐ
        String oneLine =
        processFile((BufferedReader br) -> br.readLine());

 

 


โœ”๏ธ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ์‘์šฉํ•˜๊ธฐ

๋‚ด์šฉ์ด ๋งŽ์•„์„œ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๋ถ€๋ถ„์ด ๋งŽ์„ ์ˆ˜๋ฐ–์— ์—†๋‹ค. ๊ฐ€๋ณ๊ฒŒ ํ•œ ๋ฒˆ ์ •๋ฆฌํ•ด๋ณด์ž.

โœ๏ธ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋Š” ํ•˜๋‚˜์˜ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋งŒ ๊ฐ€์ง„๋‹ค.
โœ๏ธ  ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋Š” ๋žŒ๋‹ค ํ‘œํ˜„์‹์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ๋™์ผํ•˜๋‹ค.
โœ๏ธ  ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ถ”์ƒ ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ํ•จ์ˆ˜ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ผ๊ณ  ํ•œ๋‹ค.

 

์ž๋ฐ”์—์„œ๋Š” ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ช‡ ๊ฐ€์ง€ ์ œ๊ณตํ•œ๋‹ค. java.util.function ํŒจํ‚ค์ง€์— ์กด์žฌํ•˜๋ฉฐ, ๋ช‡ ๊ฐ€์ง€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ดํŽด๋ณด์ž.

 

๐Ÿ’ฌ Predicate

@FunctionalInterface
public interface Predicate<T> {
        boolean test(T t);
        }

public <T> List<T> filter(List<T> list, Predicate<T> p) {
        List<T> results = new ArrayList<>();
        for (T t : list) {
        if (p.test(t)) {
        results.add(t);
        }
        }
        return results;
        }

// Example
        Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
        List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

Predicate<T>๋Š” test()๋ผ๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜๊ณ , ์ธ์ž๋กœ ๋ฐ›์€ ์ œ๋„ค๋ฆญ ํƒ€์ž… T๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ boolean ๊ฐ’์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ํŠน์ง•์ด๋‹ค. ์ฃผ๋กœ ์ฐธ/๊ฑฐ์ง“์— ๋Œ€ํ•œ ํŒ๋‹จ์„ ์ด์šฉํ•  ๋•Œ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.

 

๐Ÿ’ฌ Consumer

@FunctionalInterface
public interface Consumer<T> {
        void accept(T t);
        }

public <T> void forEach(List<T> list, Consumer<T> c) {
        for (T t : list) {
        c.accept(t);
        }
        }

// example
        forEach(
        Arrays.asList(1,2,3,4,5),
        (Integer i)->System.out.println(i));

Consumer<T>๋Š” accept()๋ผ๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜๋ฉฐ, ์ธ์ž๋กœ ๋ฐ›์€ T ํƒ€์ž…์„ ํ†ตํ•ด ์–ด๋– ํ•œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ๋งŒ๋“ ๋‹ค. ์ด๋•Œ, ๋ฆฌํ„ด๊ฐ’์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋™์ž‘์— ๋Œ€ํ•œ ์‹คํ–‰ ๋กœ์ง์„ ์ •์˜ํ•  ๋•Œ ํ™œ์šฉํ•˜๊ธฐ ์ข‹๋‹ค.

 

๐Ÿ’ฌ Function

@FunctionalInterface
public interface Function<T, R> {
        R apply(T t);
        }

public <T, R> List<R> map(List<T> list, Function<T, R> f) {
        List<R> result = new ArrayList<>();
        for (T t : list) {
        result.add(f.apply(t));
        }
        return result;
        }

// example
        List<Integer> l = map(
        Arrays.asList("lambdas","in","action"),
        (String s)->s.length() // [7, 2, 6] 
        );

Function<T, R> ์€ apply()๋ผ๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜๋ฉฐ, ์ธ์ž๋กœ ๋ฐ›์€ T ํƒ€์ž…์„ ํ†ตํ•ด R ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ž…๋ ฅ → ์ถœ๋ ฅ์œผ๋กœ ์–ด๋– ํ•œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์‹œ ์œ ์šฉํ•˜๋‹ค.

 

์ฐธ๊ณ ๋กœ, ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ๋‚ด๋ถ€์˜ ์ œ๋„ค๋ฆญ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๋ฌด์กฐ๊ฑด ๋ ˆํผ๋Ÿฐ์Šค ํƒ€์ž…๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋•Œ ์ž๋ฐ”์—์„œ๋Š” primitive ํƒ€์ž…์„ ๋ ˆํผ๋Ÿฐ์Šค ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ์ด๋ฅผ ‘๋ฐ•์‹ฑ(Boxing)’์ด๋ผ๊ณ  ํ•˜๊ณ , ๋ฐ˜๋Œ€์˜ ๊ณผ์ •์„ ‘์–ธ๋ฐ•์‹ฑ(Unboxing)’์ด๋ผ๊ณ  ํ•œ๋‹ค. ๋ณดํ†ต ์ž๋ฐ”์—์„œ๋Š”, ๋ฐ•์‹ฑ๊ณผ ์–ธ๋ฐ•์‹ฑ์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ์˜คํ† ๋ฐ•์‹ฑ(autoboxing)์ด ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š”๋ฐ, ํ”ํžˆ ๋ฆฌ์ŠคํŠธ์— ๊ฐ’์„ ๋„ฃ์„ ๋•Œ ๋‚ด๋ถ€ ์š”์†Œ๋Š” wrapping ๋˜์–ด ๋“ค์–ด๊ฐ„๋‹ค.

List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
        // int -> Integer๋กœ autoboxing ๊ณผ์ •์ด ์ผ์–ด๋‚œ๋‹ค. 
        list.add(i);
        }
// ArrayList.java
public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
        }

private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
        elementData = grow();

        elementData[s] = e;
        size = s + 1;
        }

๊ถ๊ธˆํ•ด์„œ ์ฐพ์•„๋ดค๋Š”๋ฐ, ์ œ๋„ค๋ฆญ์œผ๋กœ ๋ฐ›๋Š” ์‹œ์ ๋ถ€ํ„ฐ ๋ ˆํผ๋Ÿฐ์Šค ํƒ€์ž…๋งŒ ๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ปดํŒŒ์ผ๋Ÿฌ์—์„œ ์•Œ์•„์„œ wrapping ํ•ด์ค€๋‹ค๊ณ  ํŒ๋‹จํ•˜์˜€๋‹ค. ์ด๋Ÿฌํ•œ wrapping ๊ณผ์ •์€ ๊ฒฐ๊ตญ ํž™์— ์ €์žฅ๋˜๋ฉด์„œ ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋น„๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์ ์œผ๋กœ ์ด์Šˆ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์˜คํ† ๋ฐ•์‹ฑ์„ ํ”ผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

 

IntPredicate evenNumbers = (int i) -> i % 2 == 0;
// ์—ฌ๊ธฐ์„œ 1000์€ ๋ฐ•์‹ฑํ•˜์ง€ ์•Š๋Š”๋‹ค. ์˜คํ† ๋ฐ•์‹ฑ์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค.
        evenNumbers.test(1000);

        Predicate<Integer> oddNumbers = (Integer i) -> i % 2 != 0;
// Predicate<Integer>์—์„œ๋Š” 1000์ด๋ผ๋Š” ๊ฐ’์„ Integer๋กœ ๋ฐ•์‹ฑํ•˜๊ฒŒ ๋œ๋‹ค.
        oddNumbers.test(1000);

์œ„ ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉํ•˜๋Š” IntPredicate๋ฅผ ์ด์šฉํ•˜๊ฒŒ ๋˜๋ฉด, primitive ํƒ€์ž…์ธ int ๊ฐ’์„ boxing ํ•˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ Predicate<T> ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํšจ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. IntPredicate ์™ธ์—๋„ ๋‹ค์–‘ํ•œ ํƒ€์ž…์— ๋งž๋Š” Predicate๊ฐ€ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒํ™ฉ์— ๋”ฐ๋ผ์„œ ๋งž์ถฐ์„œ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค. 

 

์•„๋ž˜๋Š” ์ž๋ฐ”์—์„œ ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์™€ ๋””์Šคํฌ๋ฆฝํ„ฐ ์ •๋ณด์ด๋‹ค. (๋ฌผ๋ก  ๋” ๋งŽ์ด ์žˆ๋‹ค!)

 

ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ์ด๋ฆ„ ํ•จ์ˆ˜ ๋””์Šคํฌ๋ฆฝํ„ฐ
Predicate<T> T -> boolean
Consumer<T> T -> void
Function<T, R> T -> R
Supplier<T> () -> T
UnaryOperator<T> T->T
BinaryOperator<T> (T, T) -> T
BiPredicate<L, R> (T, U) -> boolean
BiConsumer<T, U> (T, U) -> void
BiFunction<T, U, R> (T, U) -> R

 

๐Ÿ’ฌ ์ถ”๊ฐ€์ ์œผ๋กœ, ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์—์„œ๋Š” Checked Exception์„ ๋˜์ง€์ง€ ์•Š๋Š”๋‹ค. ๊ต์žฌ์—์„œ๋Š” ๋‹จ์ˆœํžˆ ์˜ˆ์™ธ๋ฅผ ๋˜์งˆ ์ˆ˜ ์—†๋‹ค๊ณ  ๋‚˜์™€์„œ, ๋ฌด์Šจ ๋ง์ธ์ง€ ์ดํ•ด๊ฐ€ ์•ˆ ๋์—ˆ๋Š”๋ฐ, ์ •ํ™•ํ•˜๊ฒŒ ๋งํ•˜๋ฉด ์ž๋ฐ”์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ถ”์ƒ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด์„œ ๋ณ„๋„๋กœ Exception์„ throw ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋ง์ด์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ, ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ปค์Šคํ…€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•ด์„œ ๋ช…์‹œ์ ์œผ๋กœ throws์„ ํ†ตํ•ด ์ „ํŒŒ์‹œํ‚ค๊ฑฐ๋‚˜, ๋žŒ๋‹ค ์ž์ฒด๋ฅผ try - catch๋กœ ์žก์•„์„œ runtime Exception์œผ๋กœ ๊ฐ์‹ธ์„œ ์ฒ˜๋ฆฌํ•ด์ค˜์•ผ ํ•œ๋‹ค. (์‚ฌ์‹ค, ์ด๋Š” checked exception์˜ ๊ฐœ๋… ์ž์ฒด์—์„œ ๋‚˜์˜ค๋Š” ๋ฌธ์ œ๊ฐ€ ์•„๋‹Œ๊ฐ€ ์‹ถ๊ธฐ๋Š” ํ•˜๋‹ค.)

 

1) throws๋กœ ์˜ˆ์™ธ ์ „ํŒŒํ•˜๊ธฐ

@FunctionalInterface
public interface BufferedReaderProcessor {
    String process(BufferedReader b) throws IOException;
}

    BufferedReaderProcessor p = (BufferedReader br) -> br.readLine();

2) try-catch๋กœ ์žก์•„์„œ ์ฒ˜๋ฆฌํ•˜๊ธฐ

 

Function<BufferedReader, String> f = (BufferedReader b) -> {
        try {
        return b.readLine();
        } catch (IOException e) {
        throw new RuntimeException(e);
        }
        };

 

 


โœ”๏ธ ๋žŒ๋‹ค ํ‘œํ˜„์‹์€ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„์ฒด์˜ ์ •๋ณด๋ฅผ ์•Œ๊นŒ์š”?

๋žŒ๋‹ค ํ‘œํ˜„์‹์€ ๋žŒ๋‹ค๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋žŒ๋‹ค์˜ ํ˜•์‹์„ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ, ๋žŒ๋‹ค์—๊ฒŒ ์ „๋‹ฌ๋˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋‚˜ ๋ณ€์ˆ˜ ๋“ฑ ๋žŒ๋‹ค์—์„œ ์‚ฌ์šฉ๋˜๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•˜๋Š” ํ‘œํ˜„์‹์˜ ํ˜•์‹์„ ‘๋Œ€์ƒ ํ˜•์‹’์ด๋ผ๊ณ  ํ•œ๋‹ค.

List<Crew> crews = filter(wootecho, (Crew crew) ->
        crew.getCourse().equals(BACKEND));

์œ„ ์˜ˆ์ œ๋Š” ์šฐํ…Œ์ฝ” ํฌ๋ฃจ๋“ค ์ค‘์—์„œ ๋ฐฑ์—”๋“œ์ธ ํฌ๋ฃจ๋“ค๋งŒ ๋ฝ‘๋Š” ์˜ˆ์ œ์ด๋‹ค. ์œ„ ์ฝ”๋“œ์—์„œ ๋žŒ๋‹ค ํ‘œํ˜„์‹์€ ์–ด๋–ป๊ฒŒ ํ˜•์‹ ๊ฒ€์‚ฌ๋ฅผ ์ง„ํ–‰ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์ž.

 

1) filter ๋ฉ”์„œ๋“œ์˜ ์„ ์–ธ ํ™•์ธํ•˜๊ธฐ

// filterCrews์˜ ์ •์˜
public List<Crew> filterCrews(List<Crew> crews, Predicate p) {
        List<Crew> resultCrews = new ArrayList<>();
        for (Crew crew : crews) {
        if (p.test(crew) {
        resultCrews.add(crew);
        }
        }
        }

// before
        filterCrews(wootecho, (Crew crew) → crew.getCourse().equals(BACKEND))

// after
        filterCrews(wootecho, Predicate<Crew> p)

ํ˜„์žฌ, ์œ„ ์ฝ”๋“œ์—์„œ filterCrews()๋Š” ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ Predicate<Crew> ํ˜•์‹์„ ๊ธฐ๋Œ€ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ Predicate<Crew>๊ฐ€ ๋Œ€์ƒ ํ˜•์‹์ด ๋œ๋‹ค.  

 

2) Predicate<Crew>์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๊ธฐ

์ž๋ฐ”์—์„œ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณต๋˜๋Š” Predicate<T> ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋Š”, test()๋ผ๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง„๋‹ค. ์ด๋•Œ, ํ•ด๋‹น ์ถ”์ƒ ๋ฉ”์„œ๋“œ์ดใ…ก ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” T -> boolean์ด๋ฉฐ, ์œ„ ์˜ˆ์ œ์—์„œ๋Š” Crew -> boolean์ด ๋œ๋‹ค.

 

3) ํ•จ์ˆ˜ ๋””์Šคํฌ๋ฆฝํ„ฐ ๋ฌ˜์‚ฌํ•˜๊ธฐ

์ด๋•Œ, Crew๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ boolean์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ๋ฌ˜์‚ฌํ•˜๊ฒŒ ๋˜๋ฉฐ, ์ด ๊ณผ์ •์—์„œ ๋žŒ๋‹ค ํ‘œํ˜„์‹์ด ์˜ˆ์™ธ๋ฅผ ๋˜์งˆ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ถ”์ƒ ๋ฉ”์„œ๋“œ์—์„œ๋„ ์˜ˆ์™ธ๋ฅผ ๋˜์งˆ ์ˆ˜ ์žˆ๋„๋ก throws๋กœ ๋˜์ง€๊ฑฐ๋‚˜, try-catch๋กœ ์žก์•„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค. ์•„๋ฌดํŠผ, filter๋กœ ์ „๋‹ฌ๋˜๋Š” ์ธ์ˆ˜๋Š” ์œ„์™€ ๊ฐ™์€ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋งŒ์กฑํ•ด์•ผ ํ•˜๋ฉฐ, ํ˜„์žฌ ์ฝ”๋“œ์—์„œ๋Š” (Crew crew) -> crew.getCourse.equals(BACKEND); ๋ผ๋Š” ์ฝ”๋“œ ์ž์ฒด๊ฐ€ Crew -> boolean์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์žˆ์–ด์„œ 

 

 

๐Ÿ’ฌ ์ด๋•Œ, '๋Œ€์ƒ ํ˜•์‹'์ด๋ผ๋Š” ํŠน์ง• ๋•Œ๋ฌธ์—, ๋žŒ๋‹ค์‹๋งˆ๋‹ค ๊ทธ์— ํ˜ธํ™˜ํ•˜๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง„ ๋‹ค๋ฅธ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค.

Comparator<Crew> c1 =
        (Crew a1, Crew a2) -> a1.getAge().compareTo(a2.getAge());

        ToIntBiFunction<Crew, Crew> c2 =
        (Crew a1, Crew a2) -> a1.getAge().compareTo(a2.getAge());

        BiFunction<Crew, Crew, Integer> c3 =
        (Crew a1, Crew a2) -> a1.getAge().compareTo(a2.getAge());

์œ„์˜ ์„ธ ์ฝ”๋“œ ๋ชจ๋‘ Crew๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„, compareTo๋ฅผ ํ†ตํ•ด์„œ ๋น„๊ตํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด์ง€๋งŒ (๋™์ผํ•œ ๋žŒ๋‹ค์‹์ด์ง€๋งŒ) ๊ฐ๊ฐ ๋‹ค๋ฅธ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์‚ฌ์šฉ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. 

 

 

๐Ÿ’ฌ ๋žŒ๋‹ค์˜ void ํ˜ธํ™˜ ๊ทœ์น™

๋žŒ๋‹ค์˜ ๋ฐ”๋””์— ์ผ๋ฐ˜ ํ‘œํ˜„์‹์ด ์žˆ์œผ๋ฉด, void๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ ๋””์Šคํฌ๋ฆฝํ„ฐ์™€ ํ˜ธํ™˜๋œ๋‹ค.

// Predicate๋Š” ๋ถˆ๋ฆฌ์–ธ ๋ฐ˜ํ™˜๊ฐ’์„ ๊ฐ–๋Š”๋‹ค. (์ถ”๊ฐ€ํ•œ ๋’ค ์—ฌ๋ถ€ ๋ฐ˜ํ™˜)
Predicate<String> p = s -> list.add(s);

// Consumer๋Š” void ๋ฐ˜ํ™˜๊ฐ’์„ ๊ฐ–๋Š”๋‹ค. (์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ํ–‰์œ„)
        Consumer<String> b = s -> list.add(s);

list.add()๋Š” ์›๋ž˜ ๋ฐ˜ํ™˜๊ฐ’์ด boolean์ธ ๋ฉ”์„œ๋“œ์ธ๋ฐ, Predicate๋กœ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์•„๋ž˜์™€ ๊ฐ™์ด Consumer์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (์—ฌ๊ธฐ์„œ ์ผ๋ฐ˜ ํ‘œํ˜„์‹์ด๋ผ๋Š” ๋ง์ด ๊ต‰์žฅํžˆ ๋ชจํ˜ธํ•œ๋ฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž๋ฐ”๋Š” ๋ฉ”์„œ๋“œ์˜ ๋ฆฌํ„ด๊ฐ’์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ์œ„ ์˜ˆ์ œ์—์„œ๋„ ๋ฆฌํ„ด๊ฐ’์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ void๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” Consumer์™€ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด, ๋‹จ์ˆœํžˆ ๋™์ž‘ ์ž์ฒด๋งŒ ์‹คํ–‰ํ•˜๋Š” ํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์‹์œผ๋กœ ํ•˜๋Š” ๊ฒŒ ์•„๋‹๊นŒ... ๋ผ๋Š” ๊ฒŒ ๋‚ด ์ƒ๊ฐ์ด๋‹ค ๐Ÿค”)

 

 

๐Ÿ’ฌ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฉ”์„œ๋“œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ

// Java์—์„œ ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

// ๋‚ด๊ฐ€ ๋งŒ๋“  ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค
@FunctionalInterface
public interface Sample {
    void run();
}

์œ„์™€ ๊ฐ™์€ ๋‘ ๊ฐœ์˜ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์กด์žฌํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

public class Main {
    public static void main(String[] args) {
        execute(() -> {});
    }
    public static void execute(Runnable runnable) {
        runnable.run();
    }
    public static void execute(Sample sample) {
        sample.run();
    }
}

์ด๋•Œ, () → {}๋ผ๋Š” ๋””์Šคํฌ๋ฆฝํ„ฐ๊ฐ€ () → void์ธ ๋žŒ๋‹ค ํ‘œํ˜„์‹์ด ์žˆ์„ ๋•Œ, ์–ด๋–ค ๊ฑธ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ ๊นŒ?

 

Intellij์—์„œ๋Š” ๋ชจํ˜ธํ•˜๋‹ค๊ณ  ์•Œ๋ ค์ค€๋‹ค. ์ฆ‰, ์ด ๊ณผ์ •์—์„œ ๋Œ€์ƒ ํ˜•์‹์„ ํ†ตํ•ด ์ปจํ…์ŠคํŠธ๊ฐ€ ๋™์ผํ•œ ‘ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค’๋ฅผ ์ฐพ์•„๋‚˜๊ฐ€๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, ๋ช…์‹œ์ ์œผ๋กœ ์บ์ŠคํŒ…ํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•˜๋‹ค.

public static void main(String[] args) {
        execute((Sample) () -> {});
        }

๋‚˜๋Š” ๋‚ด๊ฐ€ ๋งŒ๋“  ๊ฒŒ ์ข‹์œผ๋‹ˆ๊นŒ ์ด๋ ‡๊ฒŒ ์บ์ŠคํŒ…์„ ์ง„ํ–‰ํ–ˆ๋‹ค.

 

๐Ÿ’ฌ ์ •๋ฆฌ

๐Ÿ’ก ์ž๋ฐ” ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๋žŒ๋‹ค ํ‘œํ˜„์‹์ด ์‚ฌ์šฉ๋œ ์ปจํ…์ŠคํŠธ (=๋Œ€์ƒ ํ˜•์‹)์„ ํ†ตํ•ด, ๋žŒ๋‹ค ํ‘œํ˜„์‹๊ณผ ๊ด€๋ จ๋œ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ถ”๋ก ํ•œ๋‹ค.
= ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๋žŒ๋‹ค์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๊นŒ์ง€ ์ถ”๋ก ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
= ์ฆ‰, ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ์•„๋‹ˆ๊นŒ ๋žŒ๋‹ค์˜ ๋ฌธ๋ฒ•์‹ ์ž์ฒด์—์„œ๋„ ์ด๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค!

 


โœ”๏ธ ๋žŒ๋‹ค์—์„œ๋Š” ํƒ€์ž…์„ ์ƒ๋žตํ•ด๋„ ๋œ๋‹ค๋˜๋ฐ?

์šฐ๋ฆฌ๋Š” ์œ„์—์„œ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋žŒ๋‹ค์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ์•ˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋„์ถœํ•˜์˜€๋‹ค.

// Before
List<Crew> crews = filter(wootecho, (Crew crew) ->
        crew.getCourse().equals(BACKEND));

// After
        List<Crew> crews = filter(wootecho, crew ->
        crew.getCourse().equals(BACKEND));

์ด๋Ÿฐ ์‹์œผ๋กœ, ๊ตณ์ด ๋ช…์‹œ์ ์œผ๋กœ Crew๋ผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์„ ์ง€์ •ํ•ด์ฃผ์ง€ ์•Š์•„๋„ ๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ํŠนํžˆ, ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚˜๋ฉด ๊ฐ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ชจ๋‘์—๊ฒŒ ํƒ€์ž…์„ ์ง€์ •ํ•ด์ค„ ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ์ƒ์œผ๋กœ๋„ ๋” ๊ฐ„๊ฒฐํ•ด์ง€๊ฒŒ ๋œ๋‹ค.

 

์ฆ‰, ์ •๋ฆฌํ•˜์ž๋ฉด!

1. ์ž๋ฐ” ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๋žŒ๋‹ค ํ‘œํ˜„์‹์ด ์‚ฌ์šฉ๋œ ์ปจํ…์ŠคํŠธ (๋Œ€์ƒ ํ˜•์‹)์„ ํ†ตํ•ด ๋žŒ๋‹ค ํ‘œํ˜„์‹๊ณผ ๊ด€๋ จ๋œ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ถ”๋ก ํ•œ๋‹ค.
2. ์ด๋ ‡๊ฒŒ ์ถ”๋ก ํ•œ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ๋•๋ถ„์—, ํ•จ์ˆ˜ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค. 
3. ์ฆ‰, ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๋žŒ๋‹ค์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. (์ถ”์ƒ ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜ == ๋žŒ๋‹ค์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜)
4. ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๋žŒ๋‹ค ํ‘œํ˜„์‹์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ํ˜•์‹์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋ฌธ๋ฒ•์ ์œผ๋กœ ์ƒ๋žต์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 


โœ”๏ธ ๋žŒ๋‹ค์˜ ์ง€์—ญ ๋ณ€์ˆ˜

๋žŒ๋‹ค์—์„œ๋Š” ์ต๋ช… ํ•จ์ˆ˜์ฒ˜๋Ÿผ ์™ธ๋ถ€์—์„œ ์ •์˜๋œ ๋ณ€์ˆ˜๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. (์ด๋ฅผ ์ž์œ  ๋ณ€์ˆ˜๋ผ๊ณ  ํ•˜๋Š”๋ฐ, ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ์ง„ ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹Œ, ์™ธ๋ถ€์—์„œ ์ •์˜๋œ ๋ณ€์ˆ˜ ์ž์ฒด๋ฅผ ์˜๋ฏธํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.) ์ด๋ฅผ ๋žŒ๋‹ค ์บก์ฒ˜๋ง์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ์ด๋•Œ ํ•ด๋‹น ์ง€์—ญ๋ณ€์ˆ˜๋Š” ๋ช…์‹œ์ ์œผ๋กœ final๋กœ ์„ ์–ธ๋˜์–ด ์žˆ๊ฑฐ๋‚˜, final์ฒ˜๋Ÿผ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ์ ์ด ํฐ ํŠน์ง•์ด๋‹ค. (์ธ์Šคํ„ด์Šค, ํด๋ž˜์Šค, ์ •์  ๋ณ€์ˆ˜๋Š” ์ƒ๊ด€์—†๋‹ค.)

public class Main {
    private String pobi = "I'm pobi";  // ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜ 
    private static String WOOTECO = "I'm Wooteco"; // ํด๋ž˜์Šค ๋ณ€์ˆ˜
    private static final String COACH = "I'm Coach"; // ์ •์  ๋ณ€์ˆ˜

    public void main(String[] args) {
        String crew = "I'm Crew"; // ์ง€์—ญ ๋ณ€์ˆ˜, final ์ทจ๊ธ‰์ด๋‹ค.
        Runnable r1 = () -> System.out.println(crew);
        Runnable r2 = () -> System.out.println(COACH);
        Runnable r3 = () -> System.out.println(pobi);
        Runnable r4 = () -> System.out.println(WOOTECO);

        r1.run(); // I'm Crew
        r2.run(); // I'm Coach
        r3.run(); // I'm pobi
        r4.run(); // I'm Wooteco
    }

}

 

๋งŒ์•ฝ, crew์— ๋‹ค๋ฅธ ์ด๋ฆ„์„ ํ• ๋‹นํ•˜๋ ค๊ณ  ํ•œ๋‹ค๋ฉด, Intellij์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋žŒ๋‹ค ํ‘œํ˜„์‹์€ final์ด์–ด์•ผ ํ•œ๋‹ค๊ณ  ๊ฒฝ๊ณ ํ•œ๋‹ค.

 

๐Ÿ’ฌ ์™œ ์ด๋Ÿฐ ์ œ์•ฝ์„ ๊ฑด ๊ฑธ๊นŒ?

๊ด€๋ จํ•ด์„œ๋Š” ํ”„๋กค๋กœ๊ทธ์— ๊ธ€์„ ์ž‘์„ฑํ•ด๋‘์—ˆ๋‹ค! ๐Ÿ˜Ž

 

์šฐ์•„ํ•œํ…Œํฌ์ฝ”์Šค ํ•™์Šต๋กœ๊ทธ ์ €์žฅ์†Œ

์šฐ์•„ํ•œํ…Œํฌ์ฝ”์Šค ํฌ๋ฃจ๋“ค์ด ๋ฐฐ์šด ๋‚ด์šฉ์„ ๊ธฐ๋กํ•˜๋Š” ํ•™์Šต๋กœ๊ทธ ์ €์žฅ์†Œ์ž…๋‹ˆ๋‹ค.

prolog.techcourse.co.kr

์š”์•ฝํ•˜์ž๋ฉด, ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋Š” heap, ์ •์  / ํด๋ž˜์Šค ๋ณ€์ˆ˜๋Š” static ์˜์—ญ์— ์œ„์น˜ํ•ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ์ง€์—ญ๋ณ€์ˆ˜๋Š” ์Šค๋ ˆ๋“œ ๋ณ„๋กœ ์Šคํƒ ์˜์—ญ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ผ์ดํ”„ ์‚ฌ์ดํด ์ž์ฒด๋Š” ๋ณ€์ˆ˜๊ฐ€ ์„ ์–ธ๋œ ๋ธ”๋ก์ด ๋œ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, ๋งŒ์•ฝ ๋žŒ๋‹ค์‹์„ ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ํ•œ๋‹ค๋ฉด, ์ฝ”๋“œ ๋ธ”๋ก์ด ๋๋‚ฌ์„ ๋•Œ ํ•ด๋‹น ๋ณ€์ˆ˜๋Š” ์Šคํƒ์—์„œ ์ œ๊ฑฐ๋˜์ง€๋งŒ ๋žŒ๋‹ค์‹์ด ์ˆ˜ํ–‰๋  ๋•Œ ์—ฌ์ „ํžˆ ํ•ด๋‹น ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋Ÿฌํ•œ ๊ฐ€๋Šฅ์„ฑ์„ ์—†์• ๊ธฐ ์œ„ํ•ด์„œ ๋žŒ๋‹ค๋Š” ๋ณดํ†ต ์ง€์—ญ ๋ณ€์ˆ˜์˜ ๋ณต์‚ฌ๋ณธ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋‹ค. ๋ณต์‚ฌ๋ณธ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์›๋ณธ ๋ณ€์ˆ˜์™€ ๊ฐ’์ด ๋‹ฌ๋ผ์ง€๋ฉด ์•ˆ ๋˜๊ธฐ ๋•Œ๋ฌธ์—, final ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ๋ณ€๊ฒฝ ์ž์ฒด๋ฅผ ๋ง‰์•„๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ด๋‹ค. 

 


์ฑ•ํ„ฐ 3์˜ ๊ฒฝ์šฐ ๋‚ด์šฉ์ด ๊ต‰์žฅํžˆ ๊ธธ์–ด์„œ 2๊ฐœ๋กœ ๋‚˜๋ˆ ์“ธ ์˜ˆ์ •์ด๋‹ค.

๊ฐœ์ธ์ ์œผ๋กœ ๋žŒ๋‹ค ์บก์ณ๋ง์— ๋Œ€ํ•œ ๋‚ด์šฉ์ด ๊ต‰์žฅํžˆ ์ƒ‰๋‹ฌ๋ž๋‹ค ๐Ÿ˜Ž ์–ผ๋ฅธ ๋‚จ์€ ์ฑ•ํ„ฐ๋„ ์จ์•ผ๊ฒ ๋‹ค...!

Comments