Search
Duplicate
πŸ˜€

15. λžŒλ‹€μ‹

νƒœκ·Έ
λžŒλ‹€
variable capture
ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

λžŒλ‹€μ‹(Lambda Expression)

λžŒλ‹€μ‹(Lambda Expression)μ΄λž€Β ν•¨μˆ˜λ₯Ό ν•˜λ‚˜μ˜ 식(expression)으둜 ν‘œν˜„ν•œ 것이닀. ν•¨μˆ˜λ₯Ό λžŒλ‹€μ‹μœΌλ‘œ ν‘œν˜„ν•˜λ©΄Β λ©”μ†Œλ“œμ˜ 이름이 ν•„μš” μ—†κΈ° λ•Œλ¬Έμ—, λžŒλ‹€μ‹μ€Β μ΅λͺ… ν•¨μˆ˜(Anonymous Function)의 ν•œ μ’…λ₯˜λΌκ³  λ³Ό 수 μžˆλ‹€.
읡λͺ…ν•¨μˆ˜(Anonymous Function)λž€ ν•¨μˆ˜μ˜ 이름이 μ—†λŠ” ν•¨μˆ˜λ‘œ, 읡λͺ…ν•¨μˆ˜λ“€μ€ λͺ¨λ‘ 일급 객체
λžŒλ‹€μ‹μ„ μ‚¬μš©ν•˜λ©΄ λ©”μ„œλ“œ λͺ…이 λΆˆν•„μš”ν•΄μ§€κ³ , κ΄„ν˜Έ()와 ν™”μ‚΄ν‘œ β†’λ₯Ό μ΄μš©ν•œ ν•¨μˆ˜λ₯Ό μ„ μ–Έν•˜κ²Œ λœλ‹€
// κΈ°μ‘΄ 방식 public String hello() { return "Hello World!"; } // λžŒλ‹€μ‹ 적용 () -> "Hello World!";
Java
볡사
μ΄λ ‡κ²Œ λžŒλ‹€μ‹μ΄ λ“±μž₯ν•˜κ²Œ 된 μ΄μœ λŠ”Β λΆˆν•„μš”ν•œ μ½”λ“œλ₯Ό 쀄이고, 가독성을 높이기 μœ„ν•¨μ΄λ‹€.
κ·Έλ ‡κΈ° λ•Œλ¬Έμ—Β ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ—¬ ν•¨μˆ˜λ₯Ό λ³€μˆ˜μ²˜λŸΌ μ„ μ–Έν•˜λŠ” λžŒλ‹€μ‹μ—μ„œλŠ” λ©”μ†Œλ“œμ˜ 이름이 λΆˆν•„μš”ν•˜λ‹€κ³  μ—¬κ²¨μ Έμ„œ 이λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€.
λŒ€μ‹  μ»΄νŒŒμΌλŸ¬κ°€ λ¬Έλ§₯을 μ‚΄νŽ΄ νƒ€μž…μ„ μΆ”λ‘ ν•œλ‹€. λ˜ν•œ λžŒλ‹€μ‹μœΌλ‘œ μ„ μ–Έλœ ν•¨μˆ˜λŠ” 1κΈ‰ 객체이기 λ•Œλ¬Έμ—Β Stream API의 λ§€κ°œλ³€μˆ˜λ‘œ 전달이 κ°€λŠ₯해진닀.

[ λžŒλ‹€μ‹(Lambda Expression) 의 νŠΉμ§• ]

β€’
λžŒλ‹€μ‹ λ‚΄μ—μ„œ μ‚¬μš©λ˜λŠ” μ§€μ—­λ³€μˆ˜λŠ” final이 뢙지 μ•Šμ•„λ„ μƒμˆ˜λ‘œ κ°„μ£Όλœλ‹€.
β€’
λžŒλ‹€μ‹μœΌλ‘œ μ„ μ–Έλœ λ³€μˆ˜λͺ…은 λ‹€λ₯Έ λ³€μˆ˜λͺ…κ³Ό 쀑볡될 수 μ—†λ‹€.

[ λžŒλ‹€μ‹(Lambda Expression) 의 μž₯점 ]

1.
μ½”λ“œλ₯Ό κ°„κ²°ν•˜κ²Œ λ§Œλ“€ 수 μžˆλ‹€.
2.
식에 개발자의 μ˜λ„κ°€ λͺ…ν™•νžˆ λ“œλŸ¬λ‚˜ 가독성이 높아진닀.
3.
ν•¨μˆ˜λ₯Ό λ§Œλ“œλŠ” 과정없이 ν•œλ²ˆμ— μ²˜λ¦¬ν•  수 μžˆμ–΄ 생산성이 높아진닀.
4.
λ³‘λ ¬ν”„λ‘œκ·Έλž˜λ°μ΄ μš©μ΄ν•˜λ‹€.

[ λžŒλ‹€μ‹(Lambda Expression) 의 단점 ]

1.
λžŒλ‹€λ₯Ό μ‚¬μš©ν•˜λ©΄μ„œ λ§Œλ“  무λͺ…ν•¨μˆ˜λŠ” μž¬μ‚¬μš©μ΄ λΆˆκ°€λŠ₯ν•˜λ‹€.
2.
디버깅이 μ–΄λ ΅λ‹€.
3.
λžŒλ‹€λ₯Ό λ‚¨λ°œν•˜λ©΄ λΉ„μŠ·ν•œ ν•¨μˆ˜κ°€ 쀑볡 μƒμ„±λ˜μ–΄ μ½”λ“œκ°€ μ§€μ €λΆ„ν•΄μ§ˆ 수 μžˆλ‹€.
4.
μž¬κ·€λ‘œ λ§Œλ“€κ²½μš°μ— λΆ€μ ν•©ν•˜λ‹€.

λžŒλ‹€μ‹ ν‘œν˜„λ²•

λžŒλ‹€μ‹μ€ λ§€κ°œλ³€μˆ˜ + μ‹€ν–‰λ¬Έ ν˜•νƒœλ‘œ κ΅¬μ„±λœλ‹€. 즉 μ ‘κ·Όμž, λ°˜ν™˜ν˜• λͺ¨λ‘ μƒλž΅λ˜λŠ” ꡬ쑰이닀.
λͺ¨μ–‘은 ( ) β†’ { }; ν˜•νƒœλ‘œ κ΅¬μ„±λœλ‹€. κ΄„ν˜Έ μ•ˆμ— interface ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λ₯Ό μž…λ ₯ν•˜κ³ , β†’ λ’€μ˜ { } μ•ˆμ— μ‹€ν–‰ν•  μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄ λœλ‹€.

예제 μΈν„°νŽ˜μ΄μŠ€

public interface Calculator{ public int cal(int num1, int num2); }
Java
볡사
1.
κΈ°λ³Έ μ‚¬μš©λ²• ( λ§€κ°œλ³€μˆ˜ νƒ€μž…) β†’ { }; )
public static void main(String[] args){ Caculator cal = (int num1, int num2) -> {return num1 + num2; }; System.out.println(cal.cal(1 , 2)); }
Java
볡사
2.
λ§€κ°œλ³€μˆ˜ νƒ€μž… μƒλž΅( (λ§€κ°œλ³€μˆ˜) β†’ { }; )
public static void main(String[] args){ Caculator cal = (num1, num2) -> {return num1 + num2; }; System.out.println(cal.cal(1 , 2)); }
Java
볡사
λ§€κ°œλ³€μˆ˜κ°€ 1κ°œμ΄κ±°λ‚˜ 2개 μ΄μƒμ˜ λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ΄ λͺ¨λ‘ 같을 λ•ŒλŠ” νƒ€μž…μ„ μƒλž΅ κ°€λŠ₯
3.
λ§€κ°œλ³€μˆ˜κ°€ μ—†λŠ” 경우 ( ( ) β†’ { }; )
public static void main(String[] args){ Caculator cal = () -> { System.out.println("λ§€κ°œλ³€μˆ˜κ°€ μ—†λŠ” 경우")}; cal.cal(); }
Java
볡사
4.
μ€‘κ΄„ν˜Έ μƒλž΅ ( ( ) β†’ ; )
public static void main(String[] args){ Caculator cal = (num1, num2) -> num1 + num2; System.out.println(cal.cal(1 , 2)); }
Java
볡사
μ‹€ν–‰ν•  λ¬Έμž₯이 1개일 λ•Œμ—λŠ” μ€‘κ΄„ν˜Έλ₯Ό μƒλž΅ν•  수 μžˆλ‹€. 이 λ•Œ μ€‘μš”ν•œ 점은 λ°˜ν™˜μ΄ ν•„μš”ν•œ λ©”μ„œλ“œμ˜ 경우 return ν‚€μ›Œλ“œλ₯Ό μƒλž΅ν•΄μ•Ό ν•œλ‹€.
5.
μ†Œκ΄„ν˜Έ μ€‘κ΄„ν˜Έ μƒλž΅ ( λ§€κ°œλ³€μˆ˜ β†’ ; )
public static void main(String[] args){ Caculator cal = num1 -> System.out.println(num1); cal.cal(1); }
Java
볡사
λ§€κ°œλ³€μˆ˜κ°€ 1개이고, μ‹€ν–‰ν•  λ¬Έμž₯이 1개인 경우 ( ) 와 { } λ₯Ό λͺ¨λ‘ μƒλž΅ν•  수 μžˆλ‹€.

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€(Functional Interface)

β€’
ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λž€Β μΆ”μƒ λ©”μ„œλ“œκ°€ 였직 ν•˜λ‚˜μΈ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ˜λ―Έν•œλ‹€.
β€’
ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ§Œμ΄ λžŒλ‹€μ‹μœΌλ‘œ ν‘œν˜„ κ°€λŠ₯ν•˜λ‹€.
β€’
JavaλŠ” κΈ°λ³Έμ μœΌλ‘œΒ κ°μ²΄μ§€ν–₯ 언어이기 λ•Œλ¬Έμ— 순수 ν•¨μˆ˜μ™€ 일반 ν•¨μˆ˜λ₯Ό λ‹€λ₯΄κ²Œ μ·¨κΈ‰ν•˜κ³  μžˆλ‹€. Javaμ—μ„œλŠ” 이λ₯Ό κ΅¬λΆ„ν•˜κΈ° μœ„ν•΄ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€κ°€ λ“±μž₯ν•˜κ²Œ λ˜μ—ˆλ‹€.
β€’
좔상 λ©”μ„œλ“œκ°€ ν•˜λ‚˜λΌλŠ” λœ»μ€Β default methodΒ λ˜λŠ”Β static methodΒ λŠ” μ—¬λŸ¬ 개 μ‘΄μž¬ν•΄λ„ 상관 μ—†λ‹€λŠ” λœ»μ΄λ‹€.
β€’
그리고 @FunctionalInterfaceΒ μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λŠ”λ°, 이 μ–΄λ…Έν…Œμ΄μ…˜μ€ ν•΄λ‹Ή μΈν„°νŽ˜μ΄μŠ€κ°€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ 쑰건에 λ§žλŠ”μ§€ 검사해쀀닀.
β€’
@FunctionalInterfaceΒ μ–΄λ…Έν…Œμ΄μ…˜μ΄ 없어도 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ‘œ λ™μž‘ν•˜κ³  μ‚¬μš©ν•˜λŠ” 데 λ¬Έμ œλŠ” μ—†μ§€λ§Œ, μΈν„°νŽ˜μ΄μŠ€ 검증과 μœ μ§€λ³΄μˆ˜λ₯Ό μœ„ν•΄ λΆ™μ—¬μ£ΌλŠ” 게 μ’‹λ‹€.

Variable Capture

λžŒλ‹€μ‹μ˜ μ‹€ν–‰ 블둝 λ‚΄μ—μ„œ λžŒλ‹€μ‹μ„ 감싸고 μžˆλŠ” 클래슀의 μΈμŠ€ν„΄μŠ€ λ³€μˆ˜, μŠ€νƒœν‹± λ³€μˆ˜, 지역 λ³€μˆ˜μ— μ ‘κ·Όν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.
ν•˜μ§€λ§Œ 지역 λ³€μˆ˜μ— μ ‘κ·Όν•  λ•ŒλŠ” Variable CaptureλΌλŠ” νŠΉλ³„ν•œ μž‘μ—…μ΄ μˆ˜ν–‰λ˜κΈ° λ•Œλ¬Έμ— μ œμ•½μ΄ 생긴닀.
1.
둜컬 λ³€μˆ˜λŠ”Β final으둜 μ„ μ–Έλ˜μ–΄μ•Ό ν•œλ‹€,
2.
final둜 μ„ μ–Έλ˜μ–΄ μžˆμ§€ μ•Šμ€ 둜컬 λ³€μˆ˜λŠ”Β Effectively Final(final 처럼 λ™μž‘)이어야 ν•œλ‹€. 즉, κ°’μ˜ μž¬ν• λ‹Ήμ΄ μΌμ–΄λ‚˜λ©΄ μ•ˆλœλ‹€.
μ΄λŸ¬ν•œ μ œμ•½μ‚¬ν•­μ΄ 생긴 μ΄μœ λŠ” 클래슀 내뢀에 μ„ μ–Έλœ 둜컬 클래슀(μ—¬κΈ°μ„  λžŒλ‹€μ‹)κ°€ 지역 λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•  λ•ŒλŠ” κ·Έ 값을 λ³΅μ‚¬ν•΄μ„œ μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.
이λ₯Ό Variable Capture라고 ν•œλ‹€. μ‰½κ²Œ λ§ν•˜λ©΄ Variable Captureλž€ 객체 μ™ΈλΆ€μ—μ„œ μ„ μ–Έλœ λ³€μˆ˜λ₯Ό 객체 λ‚΄λΆ€λ‘œ λ³΅μ‚¬ν•˜λŠ” ν–‰μœ„μ΄λ‹€. 지역 λ³€μˆ˜ 뿐만 μ•„λ‹ˆλΌ νŒŒλΌλ―Έν„°λ‘œ μ „λ‹¬λœ λ³€μˆ˜ λ˜ν•œ μ™ΈλΆ€μ—μ„œ μ„ μ–Έλœ λ³€μˆ˜μ΄λ―€λ‘œ 같은 κ·œμΉ™μ΄ μ μš©λœλ‹€. μ™ΈλΆ€μ—μ„œ μ„ μ–Έλœ λ³€μˆ˜λ₯Ό 직접 μ‚¬μš©ν•˜μ§€ μ•Šκ³  λ‚΄λΆ€λ‘œ λ³΅μ‚¬ν•΄μ˜€λŠ” μ΄μœ λŠ” λ³€μˆ˜μ™€ 객체의 생λͺ… 주기와 관련이 있고 μžμ„Έν•œ μ„€λͺ…은 μ•„λž˜μ™€ κ°™λ‹€.
μŠ€νƒœν‹± λ³€μˆ˜λŠ” λ©”μ„œλ“œ μ˜μ—­μ—, μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λŠ” νž™ μ˜μ—­μ—, 지역 λ³€μˆ˜λŠ” ν˜ΈμΆœμŠ€νƒμ— 각각 μƒμ„±λœλ‹€. λžŒλ‹€μ‹ λ˜ν•œ 읡λͺ… 객체의 μΈμŠ€ν„΄μŠ€μ΄κΈ° λ•Œλ¬Έμ— νž™ μ˜μ—­μ— μƒμ„±λœλ‹€. 지역 λ³€μˆ˜λŠ” ν•΄λ‹Ή λ³€μˆ˜λ₯Ό μ„ μ–Έν•œ λ©”μ„œλ“œκ°€ μ’…λ£Œλ˜λŠ” μˆœκ°„ λ©”λͺ¨λ¦¬μ—μ„œ 사라진닀. ν•˜μ§€λ§Œ 둜컬 ν΄λž˜μŠ€λŠ” μ•„μ–˜ λ‹€λ₯Έ μœ„μΉ˜μ—μ„œ μƒμ„±λ˜κΈ° λ•Œλ¬Έμ— 생λͺ…μ£ΌκΈ°κ°€ λ©”μ„œλ“œμ™€ μ „ν˜€ 상관이 μ—†λ‹€. λ”°λΌμ„œΒ μŠ€νƒœν‹± λ³€μˆ˜, μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μ™€ λ‹¬λ¦¬Β λ‘œμ»¬ ν΄λž˜μŠ€κ°€ 지역 λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜λ €κ³  ν• λ•ŒλŠ” ν•΄λ‹Ή 지역 λ³€μˆ˜κ°€ 이미 ν˜ΈμΆœμŠ€νƒμ—μ„œ μ‚¬λΌμ‘Œμ„ μœ„ν—˜μ΄ 항상 μ‘΄μž¬ν•œλ‹€.(λ§€κ°œλ³€μˆ˜λ„ λ§ˆμ°¬κ°€μ§€λ‹€) 그럼 둜컬 ν΄λž˜μŠ€λŠ” μ ˆλŒ€λ‘œ μ™ΈλΆ€μ—μ„œ μ„ μ–Έλœ λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•  수 없도둝 μ œμ•½ν•΄μ•Ό ν• κΉŒ? 그런 μ œμ•½μ„ 걸지 μ•ŠμœΌλ©΄μ„œλ„ μœ„μ—μ„œ μ–ΈκΈ‰ν•œ μœ„ν—˜μ„±μ„ μ œκ±°ν•˜κΈ° μœ„ν•΄μ„œ μžλ°”μ—μ„œλŠ” 객체 외뢀에 μ„ μ–Έλœ λ³€μˆ˜μ˜ 값을 볡사(Variable Capture)ν•˜λ©΄μ„œ λ™μ‹œμ— ν•΄λ‹Ή λ³€μˆ˜λŠ” λ°˜λ“œμ‹œ final이어야 ν•œλ‹€λŠ” μƒˆλ‘œμš΄ μ œμ•½μ„ λ§Œλ“€μ—ˆλ‹€.

λ©”μ„œλ“œ, μƒμ„±μž 레퍼런슀

λžŒλ‹€μ‹μ΄ ν•˜λ‚˜μ˜ λ©”μ„œλ“œλ§Œ ν˜ΈμΆœν•˜λŠ” 경우, λžŒλ‹€μ‹μ„ λ”μš± κ°„κ²°ν•˜κ²Œ ν‘œν˜„ν•˜λŠ” 방법이 μ‘΄μž¬ν•˜λ©° 이λ₯Ό λ©”μ„œλ“œ 레퍼런슀라고 λΆ€λ₯Έλ‹€.
Static Method Referenece
Function<String, Integer> f = (String s) -> Integer.parseInt(s); // κΈ°μ‘΄ λžŒλ‹€μ‹ Function<String, Integer> f = Integer::parseInt; // λ©”μ„œλ“œ 레퍼런슀 적용
Java
볡사
Instance Method Reference
BiFunction<String, String, Boolean> f = (s1, s2) -> s1.equals(s2); // λžŒλ‹€μ‹ BiFunction<String, String, Boolean> f = String::equals; // λ©”μ„œλ“œ 레퍼런슀
Java
볡사
이미 μƒμ„±λœ 객체의 λ©”μ„œλ“œ Reference
MyClass obj = new MyClass(); Function<String, Boolean> f = (x) -> obj.equals(x); // λžŒλ‹€μ‹ Function<String, Boolean> f = obj::equals; // λ©”μ„œλ“œ 레퍼런슀
Java
볡사
μƒμ„±μž Refernce
// λ§€κ°œλ³€μˆ˜κ°€ μžˆλŠ” μƒμ„±μž Supplier<MyClass> s = () -> new MyClass; // λžŒλ‹€μ‹ Supplier<MyClass> s = MyClass::new; // μƒμ„±μž 레퍼런슀 // λ§€κ°œλ³€μˆ˜κ°€ μ‘΄μž¬ν•˜λŠ” μƒμ„±μž Function<Integer, MyClass> f = (i) -> new MyClass(i); // λžŒλ‹€μ‹ Function<Integer, MyClass> f = MyClass::new; // μƒμ„±μž 레퍼런슀
Java
볡사