Language/Java

β˜• ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ ν‘œμ€€ API 총정리

인파_ 2023. 3. 28. 09:49

java-functional-interface-api

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ ν‘œμ€€ API

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€(functional interface)λŠ” μΆ”μƒλ©”μ„œλ“œκ°€ 1개만 μ •μ˜λœ μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν†΅μΉ­ν•˜μ—¬ μΌμ»«λŠ”λ‹€. 이 μΈν„°νŽ˜μ΄μŠ€ ν˜•νƒœμ˜ λͺ©μ μ€ μžλ°”μ—μ„œ λžŒλ‹€ ν‘œν˜„μ‹(Lambda Expression)을 μ΄μš©ν•΄ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ„ κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄μ„œ 이닀.

// @FunctionalInterface μ–΄λ…Έν…Œμ΄μ…˜μ„ μΈν„°νŽ˜μ΄μŠ€μ— λΆ™μ—¬μ£Όλ©΄, 
// 두 개 μ΄μƒμ˜ λ©”μ†Œλ“œ μ„ μ–Έ μ‹œ 컴파일 였λ₯˜λ₯Ό λ°œμƒμ‹œμΌœ 개발자의 μ‹€μˆ˜λ₯Ό 쀄일 수 μžˆλ‹€.
@FunctionalInterface
public interface Animal {
		public void method();
}

그런데 곰곰히 생각해보면 ν•¨μˆ˜μ˜ ν˜•νƒœ(Signature)λŠ” λ‹€μ–‘ν•˜λ‹€. ν•¨μˆ˜μ˜ 리턴 값이 μžˆμ„μˆ˜λ„ μ—†μ„μˆ˜λ„ 있고 λ§€κ°œλ³€μˆ˜ κ°―μˆ˜κ°€ 1개 ν˜Ήμ€ 2개일 μˆ˜λ„ μžˆλ‹€. μ΄λŸ¬ν•œ ν˜•νƒœμ˜ ν•¨μˆ˜λ₯Ό 일일히 μ •μ˜ν•΄μ„œ μ‚¬μš©ν•˜κΈ°μ—” λ„ˆλ¬΄ 양이 λ§ŽμœΌλ‹ˆ, μžλ°” κ°œλ°œμ§„λ“€μ΄ 미리 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ§Œλ“€μ–΄ μ œκ³΅ν•˜λŠ” 것이 λ°”λ‘œ 이번 μ‹œκ°„μ— 배울 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ ν‘œμ€€ API 이닀.

μžλ°”μ—μ„œ 자료ꡬ쑰λ₯Ό μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›Œν¬λ‘œ 미리 λ§Œλ“€μ–΄ μ œκ³΅ν•˜λ“―μ΄, 자주 μ‚¬μš©ν•  것 같은 λžŒλ‹€ ν•¨μˆ˜ ν˜•νƒœλ₯Ό ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ ν‘œμ€€ API둜 미리 λ§Œλ“€μ–΄ μ œκ³΅ν•΄μ€€λ‹€λΌκ³  μ΄ν•΄ν•˜λ©΄ λœλ‹€.

ν‘œμ€€ API μ’…λ₯˜

ν•¨μˆ˜μ  μΈν„°νŽ˜μ΄μŠ€ ν‘œμ€€ APIλŠ” java.util.function νŒ¨ν‚€μ§€λ‘œ μ œκ³΅λœλ‹€. 이 νŒ¨ν‚€μ§€ μ•ˆμ— μžˆλŠ” ν•¨μˆ˜μ  μΈν„°νŽ˜μ΄μŠ€ μ’…λ₯˜λ‘œλŠ” Consumer, Supplier, Function, Operator, Predicate κ°€ μžˆλ‹€. 이 μΈν„°νŽ˜μ΄μŠ€λͺ…은 각 ν•¨μˆ˜μ˜ ν˜•νƒœμ™€ λͺ©μ μ— 따라 쑰금 재미있게 뢙여진 이름인데 이에 λŒ€ν•΄μ„œλŠ” λ’€μ—μ„œ μžμ„Ένžˆ 닀룬닀.

import java.util.function.*;
ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ λ©”μ„œλ“œ ν˜•νƒœ API ν™œμš© λ§€κ°œλ³€μˆ˜ λ°˜ν™˜κ°’
Runnable void run() 맀개 λ³€μˆ˜λ₯Ό μ‚¬μš© μ•ˆν•˜κ³  리턴을 ν•˜μ§€ μ•ŠλŠ” ν•¨μˆ˜ ν˜•νƒœλ‘œ 이용
λŒ€ν‘œμ μœΌλ‘œ μ“°λ ˆλ“œμ˜ 맀개 λ³€μˆ˜λ‘œ 이용
X X
Consumer<T> void accept(T t) 맀개 λ³€μˆ˜λ₯Ό μ‚¬μš©λ§Œ ν•˜κ³  리턴을 ν•˜μ§€ μ•ŠλŠ” ν•¨μˆ˜ ν˜•νƒœλ‘œ 이용 O X
Supplier<T> T get() 맀개 λ³€μˆ˜λ₯Ό μ‚¬μš© μ•ˆν•˜κ³  λ¦¬ν„΄λ§Œ ν•˜λŠ” ν•¨μˆ˜ ν˜•νƒœλ‘œ 이용 X O
Function<T, R> R apply(T t) λ§€κ°œκ°’μ„ λ§€ν•‘(=νƒ€μž…λ³€ν™˜)ν•΄μ„œ λ¦¬ν„΄ν•˜κΈ° O O
Predicate<T> boolean test(T t) λ§€κ°œκ°’μ΄ 쑰건에 λ§žλŠ”μ§€ λ‹¨μ •ν•΄μ„œ boolean λ¦¬ν„΄ O O
Operator R applyAs(T t) λ§€κ°œκ°’μ„ μ—°μ‚°ν•΄μ„œ κ²°κ³Ό λ¦¬ν„΄ν•˜κΈ° O O

(T: 데이터 νƒ€μž…, R: 리턴 νƒ€μž…)

이 처럼 λ‹€μ–‘ν•œ ν•¨μˆ˜μ  ν˜•νƒœκ°€ 될수 μžˆλŠ” 것듀을 μΆ”λ € λͺ¨μ•„ μ •λ¦¬ν•˜μ—¬ API둜 μ œκ³΅ν•¨μœΌλ‘œμ¨, 우리 같은 κ°œλ°œμžλ“€μ€ ꡳ이 좔상 λ©”μ†Œλ“œ ν•˜λ‚˜ 가진 μΈν„°νŽ˜μ΄μŠ€λ₯Ό 일일히 μ •μ˜ν•  ν•„μš”μ—†μ΄ API 만 κ°€μ Έλ‹€ μ“°λ©΄ λ˜λŠ” 것이닀. 


ν‘œμ€€ APIλŠ” νƒ€μž… 제곡 μš©λ„μ΄λ‹€

μžλ°”μ˜ λžŒλ‹€μ‹μ„ λ³€μˆ˜λ‚˜ λ§€κ°œλ³€μˆ˜μ— ν• λ‹Ήν•˜κΈ° μœ„ν•΄μ„œλŠ” 그에 ν•΄λ‹Ήν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μ΄ ν•„μš”ν•˜λ‹€.

예λ₯Ό λ“€μ–΄ μžλ°”μŠ€ν¬λ¦½νŠΈ κ°™μ€κ²½μš° μ•½νƒ€μž… 언어이기 λ•Œλ¬Έμ— λ‹€μŒκ³Ό 같이 λ³€μˆ˜μ— ν•¨μˆ˜λ₯Ό λŒ€μž…λ§Œν•˜λ©΄ μ•Œμ•„μ„œ νƒ€μž… 좔둠이 λœλ‹€.

let a = () => {};

ν•˜μ§€λ§Œ μžλ°”λŠ” κ°•νƒ€μž… 언어이기 λ•Œλ¬Έμ— μ–΄λ– ν•œ μ •μˆ˜λ©΄ μ •μˆ˜μ— λ§žλŠ” νƒ€μž…μ„, ν•¨μˆ˜λ©΄ ν•¨μˆ˜μ— λ§žλŠ” νƒ€μž…μ„ 지정해 μ£Όμ–΄μ•Ό ν•œλ‹€. κ·Έλž˜μ„œ λžŒλ‹€ ν•¨μˆ˜λ₯Ό 담을 수 μžˆλŠ” λŒ€ν‘œν•  νƒ€μž…μ„ μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μœΌλ‘œ μ •ν•œ 것이라고 μ΄ν•΄ν•˜λ©΄ λœλ‹€. (μ •ν™•νžˆλŠ” μΈν„°νŽ˜μ΄μŠ€ 읡λͺ… κ΅¬ν˜„ 객체λ₯Ό κ°„λž΅ν™” ν•œ 것이닀)

@FunctionalInterface
public interface Animal {
		public void run();
}

// run() μ΄λΌλŠ” λ©”μ„œλ“œλ₯Ό μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μœΌλ‘œ μ„ μ–Έν•˜μ—¬ μ •μ˜
Animal a = () -> {};

그런데 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λΌκ³  ν•˜μ§€λ§Œ 사싀상 μΈν„°νŽ˜μ΄μŠ€λͺ…이 λ”±νžˆ μ •ν•΄μ Έ μžˆμ§€ μ•ŠκΈ° λ•Œλ¬Έμ— λ¬Έμ œκ°€ λ°œμƒν•œλ‹€. κ·Έλƒ₯ 좔상 λ©”μ†Œλ“œ ν•œκ°œλ§Œ 가지고 있으면 λͺ¨λ“  μΈν„°νŽ˜μ΄μŠ€λŠ” ν•¨μˆ˜μ  μΈν„°νŽ˜μ΄μŠ€λ‘œ 취급될 수 있기 λ•Œλ¬Έμ΄λ‹€.

이것이 μ™œ λ¬Έμ œλƒλ©΄ λ©”μ†Œλ“œλ₯Ό μ„€κ³„ν• λ•Œ 애맀해진닀. 만일 νŒŒλΌλ―Έν„°λ‘œ λžŒλ‹€ ν•¨μˆ˜λ₯Ό λ°›λŠ” μ–΄λ– ν•œ λ©”μ†Œλ“œλ₯Ό μ„€κ³„ν•œλ‹€κ³  ν•˜λ©΄, 이 λ§€κ°œλ³€μˆ˜μ˜ μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…λͺ…을 μ§€μ •ν•˜λŠ”λ° μ• λ‘œμ‚¬ν•­μ΄ 생긴닀. 라이브러리 μ‚¬μš©μžκ°€ μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…λͺ…을 μ–΄μ°Œ 지을지 μ–΄λ–»κ²Œ μ•Œκ³  κ°•νƒ€μž… 언어인 μžλ°”μ—μ„œ 섀계λ₯Ό ν•˜λŠλƒμΈ λ¬Έμ œμ΄λ‹€.

λ”°λΌμ„œ μžλ°” κ°œλ°œμ§„λ“€μ΄ 미리 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ 이름듀을 μ •ν•΄ μ œκ³΅ν•˜λŠ” 것이 μœ„μ˜ ν‘œμ—μ„œ λ³Έ Runnable, Consumer, Supplier, Function, Operator, Predicate μΈν„°νŽ˜μ΄μŠ€μΈ 것이닀.

 

Runnable μΈν„°νŽ˜μ΄μŠ€

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ™€ λžŒλ‹€ ν•¨μˆ˜λ₯Ό μ΄ν•΄ν•˜λŠ”λ° μžˆμ–΄ κ°€μž₯ 쒋은 것이 λ°”λ‘œ Runnable μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€. μ‹€μ œ μžλ°” νŒ¨ν‚€μ§€μ— μ •μ˜ λ˜μ–΄μžˆλŠ” Runnalbe μΈν„°νŽ˜μ΄μŠ€ μ„ μ–Έ μ½”λ“œλ₯Ό 보면 λ‹€μŒκ³Ό 같이 λ˜μ–΄ μžˆλ‹€.

java-runnable-interface

뭘 달린닀 ν˜Ήμ€ μ‹€ν–‰ν•œλ‹€λΌλŠ” μ˜λ―ΈμΈκ²ƒ 같은데 λ‹Ήμ΅œ μ΄λŸ¬ν•œ μΈν„°νŽ˜μ΄μŠ€λŠ” μ™œ λ§Œλ“€μ—ˆλŠ”μ§€ 어디에 μ‚¬μš©λ˜λŠ”μ§€ 애맀λͺ¨ν˜Έν•˜λ‹€.

μ•žμ„œ λ§ν–ˆλ“―μ΄ μ΄λŸ¬ν•œ μΈν„°νŽ˜μ΄μŠ€λ“€μ„ λ§Œλ“  μ΄μœ λŠ” λžŒλ‹€ ν•¨μˆ˜μ˜ νƒ€μž…λͺ…을 미리 μ§€μ •ν•˜κΈ° μœ„ν•΄μ„œ 라고 ν–ˆλ‹€. 즉, λ§€κ°œλ³€μˆ˜λ₯Ό 받지도 μ•Šκ³  리턴값이 μ—†κ³  κ·Έλƒ₯ μ‹€ν–‰λ§Œ ν•˜λŠ” λžŒλ‹€ ν•¨μˆ˜ ν˜•νƒœλ₯Ό λ°›λŠ” λ©”μ„œλ“œλ₯Ό μ„€κ³„ν• λ•Œ λžŒλ‹€ λ§€κ°œλ³€μˆ˜μ˜ μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μ„ Runnable둜 μ„€μ •ν•˜λ©΄ λ˜λŠ” 것이닀. 그리고 κ·Έ λ©”μ†Œλ“œκ°€ λ°”λ‘œ μš°λ¦¬κ°€ 잘 μ•„λŠ” Thread 클래슀의 λ©”μ„œλ“œ(μƒμ„±μž)이닀.

Thread thread = new Thread( () -> {
    for(int i = 0; i < 10; i++) {
        System.out.println(i);
    }
} );

μ‹€μ œ Thread 클래슀 μ •μ˜λ¬Έμ— κ°€μ„œ μƒμ„±μž ν˜•νƒœλ₯Ό 보면 λ‹€μŒκ³Ό 같이 νŒŒλΌλ―Έν„°λ‘œ Runnalbe νƒ€μž…μ˜ target λ³€μˆ˜λ₯Ό λ°›μ•„ μ‚¬μš©ν•œ λ‹€λŠ” 것을 λ³Ό 수 μžˆλ‹€.

java-runnable-interface

이것이 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ ν‘œμ€€ API의 쑴재 μ΄μœ λ‹€. Runnalbe외에도 μ—¬λŸ¬κ°€μ§€ μžλ°” λ©”μ†Œλ“œμ—μ„œ 미리 νŒŒλΌλ―Έν„° νƒ€μž…μœΌλ‘œ μ •μ˜λœ μ—¬λŸ¬ μ’…λ₯˜μ˜ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ ν‘œμ€€ API에 μ •μ˜λœ νƒ€μž…μ„ 받도둝 μ„€κ³„ν•˜μ˜€κΈ° λ•Œλ¬Έμ— 자유둭게 λžŒλ‹€μ‹μ„ ν• λ‹Ή ν•  수 μžˆλŠ” 것이닀.


ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ API μ‚¬μš©λ²•

μ΄μ œλΆ€ν„° ν•¨μˆ˜μ  μΈν„°νŽ˜μ΄μŠ€ API의 ꡬ체적인 μ‚¬μš©λ²•μ— λŒ€ν•΄ μƒμ„Ένžˆ μ•Œμ•„λ³Ό μ‹œκ°„μ„ κ°€μ§ˆν…λ°, μ—„μ²­λ‚œ μ–‘μ˜ ν‘œμ€€ APIλ₯Ό 보고 μ ˆλŒ€ 겁먹지 말자. μ ˆλŒ€λ‘œ 일일히 λ‹€ μ™Έμš°λ € ν•˜μ§€λ§κ³  String μ΄λ‚˜ List 클래슀의 λ©”μ„œλ“œ 처럼 ν•„μš”ν• λ•Œλ§ˆλ‹€ μ°Ύμ•„μ„œ μ‚¬μš©ν•˜λ©΄ λœλ‹€.

이 ν‘œμ€€ API듀은 사싀상 μ•Œκ³ λ³΄λ©΄ 별거 μ•„λ‹Œ λ†ˆλ“€μ΄λ‹€. λ‹¨μ–΄λ§Œ κ·ΈλŸ΄μ‹Έν•˜κ²Œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ API 라고 ν•˜μ§€, κ·Έλƒ₯ λžŒλ‹€μ‹μ„ μ΄μš©ν•΄ ν”„λ‘œκ·Έλž˜λ°ν• λ•Œ 자주 μ‚¬μš©λ κ²ƒ 같은 ν•¨μˆ˜ λͺ¨μ–‘, ν˜•νƒœλ₯Ό 미리 λ§Œλ“€μ–΄λ†“κ³  μΈν„°νŽ˜μ΄μŠ€ μ΄λ¦„λ§Œ μ•„μ£Ό κ·ΈλŸ΄μ‹Έν•˜κ²Œ μ „λ¬Έκ°€ 처럼 지어놓은 것 뿐이닀.

예λ₯Όλ“€μ–΄ λ°”λ‘œ λ‹€μŒμ— 배울 Consumer μΈν„°νŽ˜μ΄μŠ€ API도 κ·Έλƒ₯ λ­”κ°€ λŒ€λ‹¨ν•œ μžλ£Œν˜• 마λƒ₯ λ³΄μ΄κ² μ§€λ§Œ, κ·Έλƒ₯ λ§€κ°œλ³€μˆ˜λ§Œ λ°›κ³  λ°˜ν™˜κ°’이 μ—†λŠ” ν˜•νƒœμ˜ ν•¨μˆ˜λ₯Ό ν‘œν˜„ν•˜κΈ° μœ„ν•΄ 'μ†ŒλΉ„' λΌλŠ” 단어λ₯Ό 골라 넣은 것 뿐이닀. 그리고 μžλ°”μ—λŠ” νƒ€μž…μ΄ μ—¬λŸ¬κ°œμ΄λ‹ˆ 각 νƒ€μž…λ“€μ— 맞좰 Consumer λ₯Ό μ—¬λŸ¬κ°œλ‘œ κ΅¬μ„±ν•œ 것이닀.

이 점을 μœ μ˜ν•΄μ„œ μΈν„°νŽ˜μ΄μŠ€ ν‘œμ€€ APIλ₯Ό μ‚΄νŽ΄λ³΄λ©΄ 곡뢀에 λŒ€ν•œ κ±°λΆ€κ°μ΄λ‚˜ 압박감 없이 μŠ€λ¬΄μŠ€ν•˜κ²Œ ν•™μŠ΅ ν•  수 μžˆμ„ 것이닀.


Consumer μΈν„°νŽ˜μ΄μŠ€

  • μ—­ν•  : λ§€κ°œκ°’λ§Œ λ°›κ³  처리 (리턴값 X)
  • μ‹€ν–‰ λ©”μ„œλ“œ : accept()
  • μ†ŒλΉ„(consume)ν•œλ‹€λŠ” 말은 μ‚¬μš©λ§Œ ν•  뿐 리턴값이 μ—†λ‹€λŠ” 뜻으둜 보면 λœλ‹€.
μΈν„°νŽ˜μ΄μŠ€ ν˜•νƒœ λ‚΄μš©
Consumer<T> T ν˜•νƒœμ˜ μΈμžκ°’μ„ λ°›λŠ”λ‹€
BiConsumer<T, U> T, U ν˜•νƒœμ˜ μΈμžκ°’ 2개λ₯Ό λ°›λŠ”λ‹€
XXXConsumer XXX ν˜•νƒœμ˜ μΈμžκ°’μ„ λ°›λŠ”λ‹€
ObjXXXConsumer<T> T, XXX ν˜•νƒœμ˜ μΈμžκ°’ 2개λ₯Ό λ°›λŠ”λ‹€
BiConsumer의 Bi λœ»μ€, λΌν‹΄μ–΄μ—μ„œ νŒŒμƒλœ μ˜μ–΄ 접두사 bi- 둜 "λ‘˜"을 μ˜λ―Έν•œλ‹€. λ”°λΌμ„œ λ§€κ°œλ³€μˆ˜λ₯Ό λ‘κ°œ λ°›λŠ”λ‹€λ‘œ μ΄ν•΄ν•˜λ©° μ•”κΈ°ν•˜λ©΄ λœλ‹€.

 

Consumer μ’…λ₯˜

 μΈν„°νŽ˜μ΄μŠ€ λͺ…  μΆ”상 λ©”μ†Œλ“œ  μ„€λͺ…
 Consumer<T>  void accept(T t)  κ°μ²΄ Tλ₯Ό λ°›μ•„ μ†ŒλΉ„
 BiConsumer<T, U>  void accept(T t, U u)  κ°μ²΄ T와 Uλ₯Ό λ°›μ•„ μ†ŒλΉ„
 DoubleConsumer  void accept(double value)  double 값을 λ°›μ•„ μ†ŒλΉ„
 IntConsumer  void accept(int value)  int 값을 λ°›μ•„ μ†ŒλΉ„
 LongConsumer  void accept(long value)  long 값을 λ°›μ•„ μ†ŒλΉ„
 ObjDoubleConsumer<T>  void accept(T t, double value)  κ°μ²΄ T와 double 값을 λ°›μ•„ μ†ŒλΉ„
 ObjIntConsumer<T>  void accept(T t, int value)  κ°μ²΄ T와 int 값을 λ°›μ•„ μ†ŒλΉ„
 ObjLongConsumer<T>  void accept(T t, long value)  κ°μ²΄ T와 long 값을 λ°›μ•„ μ†ŒλΉ„
public static void main(String[] args) {

    // 객체 Tλ₯Ό λ°›μ•„ 좜λ ₯ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    Consumer<String> c1 = t -> System.out.println("μž…λ ₯κ°’ : "+ t);
    c1.accept("홍길동");

    // 객체 T와 Uλ₯Ό λ°›μ•„ 좜λ ₯ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    BiConsumer<String, Integer> c2 =  (a, b) -> System.out.println("μž…λ ₯κ°’1 : "+ a+ ", μž…λ ₯κ°’2 : "+ b);
    c2.accept("홍길동", 100);

    // int 값을 λ°›μ•„ 좜λ ₯ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    IntConsumer c3 = a -> System.out.println("μž…λ ₯κ°’ : "+ a);
    c3.accept(100);

    // double 값을 λ°›μ•„ 좜λ ₯ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    DoubleConsumer c4 = a -> System.out.println("μž…λ ₯κ°’ : "+ a);
    c4.accept(100.01);

    // long 값을 λ°›μ•„ 좜λ ₯ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    LongConsumer c5 = a -> System.out.println("μž…λ ₯κ°’ : "+ a);
    c5.accept(2100000000);
}

java-Consumer

만일 3개 μ΄μƒμ˜ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ” λžŒλ‹€ ν•¨μˆ˜λ₯Ό λ§Œλ“€κ³  μ‹Άλ‹€λ©΄, 직접 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ •μ˜ν•΄μ„œ μ‚¬μš©ν•˜μ—¬μ•Ό ν•œλ‹€.

interface TripleConsumer<T, U, K> {
    void accept(T t, U u, K k);
}

public class Main {
    public static void main(String[] args) {

        TripleConsumer<String, Double, Integer> c1 = (t, u, k) -> {
        	System.out.printf("%s + %f + %d", t, u, k);
        };
        
        c1.accept("μ•ˆλ…•", 101.23, 999);
    }
}

Supplier μΈν„°νŽ˜μ΄μŠ€

  • μ—­ν•  : 아무 λ§€κ°œκ°’ 없이 λ¦¬ν„΄κ°’λ§Œμ„ λ°˜ν™˜
  • μ‹€ν–‰ λ©”μ„œλ“œ : getXXX()
  • 생산(supply)ν•œλ‹€λŠ” 말은 데이터λ₯Ό λ°˜ν™˜(곡급) ν•œλ‹€λŠ” 뜻으둜 보면 λœλ‹€.
μΈν„°νŽ˜μ΄μŠ€ ν˜•νƒœ λ‚΄μš©
Supplier<T> Tν˜• λ°˜ν™˜
XXXSupplier XXXν˜• λ°˜ν™˜

 

Supplier μ’…λ₯˜

 μΈν„°νŽ˜μ΄μŠ€ λͺ…  μΆ”상 λ©”μ†Œλ“œ  μ„€λͺ…
 Supplier<T>  T get()  T 객체λ₯Ό 리턴
 BooleanSupplier  Boolean getAsBoolean()  Boolean 값을 리턴
 DoubleSupplier  double getAsDouble()  double 값을 리턴
 IntSupplier  int getAsInt()  int 값을 리턴
 LongSupplier  long getAsLong()  long 값을 λ¦¬ν„΄
public static void main(String[] args) {

    // T 객체λ₯Ό λ¦¬ν„΄ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    Supplier<Object> supplier = () -> new Object();
    System.out.println(supplier.get());

    // Boolean 값을 λ¦¬ν„΄ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    BooleanSupplier booleanSup =  () -> true;
    System.out.println(booleanSup.getAsBoolean());

    // int 값을 λ¦¬ν„΄ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    IntSupplier intSup = () -> {
        int num = (int) (Math.random() * 6) + 1;
        return num;
    };
    System.out.println("μ£Όμ‚¬μœ„ 랜덀 숫자 : " + intSup.getAsInt());

    // double 값을 λ¦¬ν„΄ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    DoubleSupplier doubleSup = () -> 1.0;
    System.out.println(doubleSup.getAsDouble());

    // long 값을 λ¦¬ν„΄ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    LongSupplier longSup = () -> 1L;
    System.out.println(longSup.getAsLong());
}

Supplier-inteface


Function μΈν„°νŽ˜μ΄μŠ€

  • μ—­ν•  : 맀핑(νƒ€μž… λ³€ν™˜)ν•˜κΈ°
  • μ‹€ν–‰ λ©”μ„œλ“œ : applyXXX()
  • 맀핑 ν•œλ‹€λŠ” 말은, 예λ₯Όλ“€μ–΄ μ—¬λŸ¬ 데이터 ν•­λͺ©λ“€μ΄ 듀은 κ°μ²΄μ—μ„œ νŠΉμ • νƒ€μž… 값을 μΆ”μΆœν•˜κ±°λ‚˜ ν˜Ήμ€ λ‹€λ₯Έ νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•˜λŠ” μž‘μ—…μ— μ‚¬μš©ν•œλ‹€κ³  보면 λœλ‹€.
μΈν„°νŽ˜μ΄μŠ€ ν˜•νƒœ λ‚΄μš©
Function<T, R> T λ°›μ•„μ„œ R 리턴
BiFunction<T, U, R> T, U λ°›μ•„μ„œ R 리턴
XXXFunction<T> XXX λ°›μ•„μ„œ T 리턴
XXXtoYYYFunction XXX λ°›μ•„μ„œ YYY 리턴
toXXXFunction<T> T λ°›μ•„μ„œ XXX 리턴
toXXXBiFunction<T, U> T, U λ°›μ•„μ„œ XXX 리턴
T와 UλŠ” λ§€κ°œλ³€μˆ˜ νƒ€μž…μ΄κ³  R을 리턴(return) νƒ€μž… κΈ°ν˜Έν•˜κ³  보면 λœλ‹€.

 

Function μ’…λ₯˜

 μΈν„°νŽ˜μ΄μŠ€ λͺ…  μΆ”상 λ©”μ†Œλ“œ  μ„€λͺ…
 Function<T, R>  R apply(T t)  κ°μ²΄ Tλ₯Ό 객체 R둜 맀핑
 BiFunction<T, U, R>  R apply(T t, U u)  κ°μ²΄ T와 Uλ₯Ό 객체 R둜 맀핑
 DoubleFunction<R>  R apply(double value)  double을 객체 R둜 맀핑
 IntFunction<R>  R apply(int value)  intλ₯Ό 객체 R둜 맀핑
 IntToDoubleFunction  double applyAsDouble(int value)  intλ₯Ό double둜 맀핑
 IntToLongFunction  long applyAsLong(int value)  intλ₯Ό long으둜 맀핑
 LongToDoubleFunction  double applyAsDouble(long value)  long을 double둜 맀핑
 LongToIntFunction  int applyAsInt(long value)  long을 int둜 맀핑
 ToDoubleBiFunction<T, U>  double applyAsDouble(T t, U u)  κ°μ²΄ T와 Uλ₯Ό double둜 맀핑
 ToDoubleFunction<T>  double applyAsDouble(T value)  κ°μ²΄ Tλ₯Ό double둜 맀핑
 ToIntBiFunction<T, U>  int applyAsInt(T t, U u)  κ°μ²΄ T와 Uλ₯Ό int둜 맀핑
 ToIntFunction<T>  int applyAsInt(T t)  κ°μ²΄ Tλ₯Ό int둜 맀핑
 ToLongBiFunction<T, U>  long applyAsLong(T t, U u)  κ°μ²΄ T와 Uλ₯Ό long으둜 맀핑
 ToLongFunction<T>  long applyAsLong(T t)  κ°μ²΄ Tλ₯Ό long으둜 맀핑
public static void main(String[] args) {

    // intν˜•μ„ String으둜 νƒ€μž… λ³€ν™˜ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    Function<Integer, String> intToStr = t -> String.valueOf(t);
    String str = intToStr.apply(100);

    // String을 intν˜•μœΌλ‘œ νƒ€μž… λ³€ν™˜ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    ToIntFunction<String> strToInt = t -> Integer.parseInt(t);
    int num = strToInt.applyAsInt("100");

    // intν˜•μ„ doubleν˜•μœΌλ‘œ νƒ€μž… λ³€ν™˜ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    IntToDoubleFunction intToDouble = t -> (double) t;
    double d = intToDouble.applyAsDouble(100);
}

Function-interface

class Student {
    private String name;

    int korean_score;
    int english_score;
    int math_score;

    Student(String name, int korean_score, int english_score, int math_score) {
        this.name = name;
        this.korean_score = korean_score;
        this.english_score = english_score;
        this.math_score = math_score;
    }

    String getName() {
        return name;
    }
}
public static void main(String[] args) {

    List<Student> list = List.of(
            new Student("홍길동", 99, 12, 45),
            new Student("μž„κΊ½μ •", 76, 20, 8),
            new Student("고담덕", 36, 50, 33),
            new Student("κΉ€μ’Œμ§„", 77, 89, 91)
    );

    // 각 ν•™μƒμ˜ 이름 κ°€μ Έμ˜€λŠ” ν•¨μˆ˜ μ •μ˜ (λ§€κ°œνƒ€μž… : Student 객체, λ¦¬ν„΄νƒ€μž… : Stringν˜•)
    Function<Student, String> getNameFunc = (s) -> s.getName();

    // 각 ν•™μƒμ˜ ꡐ과λͺ© 평균 κ³„μ‚°ν•˜κ³  κ°€μ Έμ˜€λŠ” ν•¨μˆ˜ μ •μ˜ (λ§€κ°œνƒ€μž… : Student 객체, λ¦¬ν„΄νƒ€μž… : intν˜•)
    ToDoubleFunction<Student> getScoreFunc = (s) -> {
        int sum = s.korean_score + s.english_score + s.korean_score;
        double avg = sum / 3.0;
        return avg;
    };

    for (Student student : list) {
        String name = getNameFunc.apply(student);
        double avg = getScoreFunc.applyAsDouble(student);
        System.out.printf("%s 평균 점수 : %f\n", name, avg);
    }
}

Function-interface


Operator μΈν„°νŽ˜μ΄μŠ€

  • μ—­ν•  : λ§€κ°œκ°’ κ³„μ‚°ν•΄μ„œ λ™μΌν•œ νƒ€μž…μœΌλ‘œ λ¦¬ν„΄ν•˜κΈ°
  • μ‹€ν–‰ λ©”μ„œλ“œ : applyXXX()
  • Functionκ³Ό λΉ„μŠ·ν•˜μ§€λ§Œ, λ§€κ°œκ°’μ„ λ¦¬ν„΄κ°’μœΌλ‘œ 맀핑(νƒ€μž… λ³€ν™˜)ν•˜λŠ” μ—­ν• λ³΄λ‹€λŠ” λ§€κ°œκ°’μ„ μ΄μš©ν•΄μ„œ 연산을 μˆ˜ν–‰ν•œ ν›„ λ™μΌν•œ νƒ€μž…μœΌλ‘œ 리턴값을 μ œκ³΅ν•˜λŠ” 역할에 초점이 κ°€μžˆλ‹€.
μΈν„°νŽ˜μ΄μŠ€ ν˜•νƒœ λ‚΄μš©
UnaryOprater<T> Tνƒ€μž… μ—°μ‚°ν•˜κ³  리턴
BinaryOperator<T> Tνƒ€μž… μ—°μ‚°ν•˜κ³  리턴
XXXUnaryOperator XXX νƒ€μž… 1개 μ—°μ‚°
XXXBinaryOperator XXX νƒ€μž… 2개 μ—°μ‚°
UnaryλŠ” 단항(연산이 1개) 이고, BinaryλŠ” 이항(연산이 2개) μ΄λΌλŠ” λœ»μ΄λ‹€.

 

Operator μ’…λ₯˜

 μΈν„°νŽ˜μ΄μŠ€ λͺ…  μΆ”상 λ©”μ†Œλ“œ  μ„€λͺ…
 UnaryOperator<T>  T apply(T t)
 Function<T, R>의 ν•˜μœ„ μΈν„°νŽ˜μ΄μŠ€
 Tλ₯Ό μ—°μ‚°ν•œ ν›„ R 리턴
 BinaryOperator<T>  T apply(T t, T u)  
 BiFunction<T, U, R>의 ν•˜μœ„ μΈν„°νŽ˜μ΄μŠ€
 T와 Uλ₯Ό μ—°μ‚° ν›„ R 리턴
 DoubleUnaryOperator  double applyAsDouble(double)  ν•œ 개의 double을 μ—°μ‚°
 DoubleBinaryOperator  double applyAsDouble(double, double)  λ‘ 개의 double을 μ—°μ‚°
 IntUnaryOperator  int applyAsInt(int)  ν•œ 개의 intλ₯Ό μ—°μ‚°
 IntBinaryOperator  int applyAsInt(int, int)  λ‘ 개의 intλ₯Ό μ—°μ‚°
 LongUnarayOperator  long applyAsLong(long)  ν•œ 개의 long을 μ—°μ‚°
 LongBinaryOperator  long applyAsLong(long, long)  λ‘ 개의 long을 μ—°μ‚°
class Operation {
    static int calculate(int[] arr, IntBinaryOperator o) {
        int result = arr[0];

        for (int i = 1; i < arr.length; i++) {
            result = o.applyAsInt(result, arr[i]);
        }

        return result;
    }
}
public static void main(String[] args) {

    int[] numbers = {3, 1, 7, 6, 5};

    // λ°°μ—΄ μš”μ†Œμ˜ λͺ¨λ“  ν•© κ΅¬ν•˜κΈ°
    int sum = Operation.calculate(numbers, (x, y) -> {
        return x + y;
    });
    System.out.println(sum);

    // λ°°μ—΄ μš”μ†Œμ˜ λͺ¨λ“  κ³± κ΅¬ν•˜κΈ°
    int mul = Operation.calculate(numbers, (x, y) -> {
        return x * y;
    });
    System.out.println(mul);

    // λ°°μ—΄ μš”μ†Œμ€‘ κ°€μž₯ 큰 수 κ΅¬ν•˜κΈ°
    int max = Operation.calculate(numbers, (x, y) -> {
        int tmp;

        if(x > y)
            tmp = x;
        else
            tmp = y;

        return tmp;
    });
    System.out.println(max);

    // λ°°μ—΄ μš”μ†Œμ€‘ κ°€μž₯ μž‘μ€ 수 κ΅¬ν•˜κΈ°
    int min = Operation.calculate(numbers, (x, y) -> {
        int tmp;

        if(x < y)
            tmp = x;
        else
            tmp = y;

        return tmp;
    });
    System.out.println(min);
}

operator-interface


Predicate μΈν„°νŽ˜μ΄μŠ€

  • μ—­ν•  : λ§€κ°œκ°’μ„ λ°›κ³  true / false 리턴
  • μ‹€ν–‰ λ©”μ„œλ“œ : test()
  • λ§€κ°œκ°’μ„ λ°›μ•„ μ°Έ/거짓을 단정(predicate) ν•œλ‹€κ³  μƒκ°ν•˜λ©΄ λœλ‹€.
μΈν„°νŽ˜μ΄μŠ€ ν˜•νƒœ λ‚΄μš©
Predicate<T> T λ₯Ό λ°›μ•„ boolean 리턴
BiPredicate<T, U> T, Uλ₯Ό λ°›μ•„ boolean 리턴
XXXPredicate XXXλ₯Ό λ°›μ•„ boolean 리턴

 

Predicate μ’…λ₯˜

 μΈν„°νŽ˜μ΄μŠ€ λͺ…  μΆ”상 λ©”μ†Œλ“œ  μ„€λͺ…
 Predicate<T>  Boolean test(T t)  κ°μ²΄ Tλ₯Ό 쑰사
 BiPredicate<T, U>  Boolean test(T t, U u)  κ°μ²΄ T와 Uλ₯Ό 비ꡐ 쑰사
 DoublePredicate  Boolean test(double value)  double 값을 쑰사
 IntPredicate  Boolean test(int value)  int 값을 쑰사
 LongPredicate  Boolean test(long value)  long 값을 쑰사
class Student {
    String name;
    int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
}
public static void main(String[] args) {

    List<Student> list = List.of(
            new Student("홍길동", 99),
            new Student("μž„κΊ½μ •", 76),
            new Student("고담덕", 36),
            new Student("κΉ€μ’Œμ§„", 77)
    );

    // intν˜• λ§€κ°œκ°’μ„ λ°›μ•„ νŠΉμ • 점수 이상이면 true μ•„λ‹ˆλ©΄ false λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜ μ •μ˜
    IntPredicate scoring = (t) -> {
        return t >= 60;
    };

    for (Student student : list) {
        String name = student.name;
        int score = student.score;
		
        // ν•¨μˆ˜ μ‹€ν–‰ν•˜μ—¬ μ°Έ / 거짓 κ°’ μ–»κΈ°
        boolean pass = scoring.test(score);
        
        if(pass) {
            System.out.println(name + "λ‹˜ " + score + "점은 κ΅­μ–΄ ν•©κ²©μž…λ‹ˆλ‹€.");
        } else {
            System.out.println(name + "λ‹˜ " + score + "점은 κ΅­μ–΄ λΆˆν•©κ²©μž…λ‹ˆλ‹€.");
        }
    }
}

Predicate-interface


ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ λ””ν΄νŠΈ λ©”μ„œλ“œ

 

Function ν•©μ„±

μ€‘κ³ λ“±ν•™μƒλ•Œ μˆ˜ν•™ μ‹œκ°„μ— f(x) ν•¨μˆ˜μ™€ g(x) ν•¨μˆ˜κ°€ μžˆμ„ λ•Œ, 이 두 ν•¨μˆ˜λ₯Ό ν•©μ„±ν•˜μ—¬ f(g(x)) λΌλŠ” ν•©μ„± ν•¨μˆ˜λ₯Ό 닀뀄본 기얡이 μ–΄λ ΄ν’‹μ΄λ‚˜λ§ˆ μžˆμ„ 것이닀. f(g(x)) λŠ” g(x)의 κ²°κ³Όλ₯Ό λ‹€μ‹œ f(x) ν•¨μˆ˜μ˜ 인자둜 λ„£μ–΄μ€€ 것이닀. 

이처럼 두 λžŒλ‹€ ν•¨μˆ˜λ₯Ό μ—°κ²°ν•˜μ—¬ ν•©μ„±μ‹œν‚¬ 수 μžˆλŠ”λ°, 이 ν•©μ„± μ‹œν‚€λŠ” λ©”μ„œλ“œλ₯Ό μžλ°”μ—μ„œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ λ””ν΄νŠΈ λ©”μ„œλ“œλ‘œμ„œ μ œκ³΅ν•œλ‹€.

μΈν„°νŽ˜μ΄μŠ€ λ©”μ„œλ“œ μ„€λͺ…
default <V> Function <T, V> andThen (Function <? super R, ? extends V> after); f(g(x)) ν•©μ„±ν•¨μˆ˜
default <V> Function <V, R> compose(Function <? super V, ? extends T> before); g(f(x)) ν•©μ„±ν•¨μˆ˜ (andThen의 λ°˜λŒ€)
static <T> Function<T, T> identity(); ν•­λ“±ν•¨μˆ˜ (자기 μžμ‹  λ°˜ν™˜)

μžλ°”-μΈν„°νŽ˜μ΄μŠ€-ν•©μ„±

ν•©μ„± ν•¨μˆ˜λŠ” Function μΈν„°νŽ˜μ΄μŠ€ 뿐만 μ•„λ‹ˆλΌ Consumer μ΄λ‚˜ Operator μΈν„°νŽ˜μ΄μŠ€λ„ μ‘΄μž¬ν•œλ‹€.

μžλ°”-μΈν„°νŽ˜μ΄μŠ€-ν•©μ„±

 

λžŒλ‹€ ν•©μ„± μ‚¬μš© μ˜ˆμ‹œ 1

κ°„λ‹¨ν•œ μˆ˜ν•™ ν•¨μˆ˜λ₯Ό μ½”λ“œλ‘œ ν‘œν˜„ν•΄ λ³΄μ•˜λ‹€. 숫자λ₯Ό λ°›μœΌλ©΄ 4λ₯Ό λΉΌλŠ” ν•¨μˆ˜ f(x) 와 숫자λ₯Ό λ°›μœΌλ©΄ 두배 κ³±ν•΄μ£ΌλŠ” ν•¨μˆ˜ g(x) λ₯Ό λžŒλ‹€ν‘œν˜„μ‹μœΌλ‘œ μ„ μ–Έν•˜μ˜€λ‹€. 그리고 이 λ‘˜μ„ andThen κ³Ό compose둜 ν•©μ„±ν•˜μ—¬ μ‚¬μš©ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

public static void main(String[] args) {

    Function<Integer, Integer> f = num -> (num - 4); // f(x)
    Function<Integer, Integer> g = num -> (num * 2); // g(x)

    // f(g(x))
    int a = f.andThen(g).apply(10);
    System.out.println(a); // (10 - 4) * 2 = 12

    // g(f(x)) - andThen을 λ°˜λŒ€λ‘œ ν•΄μ„ν•˜λ©΄ λœλ‹€
    int b = f.compose(g).apply(10);
    System.out.println(b); // 10 * 2 - 4 = 16

}

andThen κ³Ό compose 의 μ°¨μ΄λŠ” κ°„λ‹¨ν•˜λ‹€.

f.andThen(g) λ₯Ό μˆ˜ν–‰ν•˜λ©΄ f ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œ κ²°κ³Ό 값을 λ‹€μ‹œ g ν•¨μˆ˜μ˜ 인자둜 μ „λ‹¬ν•˜μ—¬ κ²°κ³Όλ₯Ό μ–»κ²Œ λœλ‹€. 단, f ν•¨μˆ˜μ˜ 리턴 νƒ€μž…μ΄ g ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜ νƒ€μž…κ³Ό ν˜Έν™˜λ˜μ–΄μ•Ό ν•œλ‹€.

f.compose(g) λ₯Ό μˆ˜ν–‰ν•˜λ©΄ g ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œ κ²°κ³Ό 값을 λ‹€μ‹œ f ν•¨μˆ˜μ˜ 인자둜 μ „λ‹¬ν•˜μ—¬ κ²°κ³Όλ₯Ό μ–»κ²Œ λœλ‹€. 즉, andThen의 λ°˜λŒ€ 버전이라고 보면 λœλ‹€.

즉, x.andThen(y) λŠ” y.compose(x) 와 λ™μΌν•˜λ‹€κ³  보면 λœλ‹€.

 

λžŒλ‹€ ν•©μ„± μ‚¬μš© μ˜ˆμ‹œ 2

λ‹€μŒ Member ν΄λž˜μŠ€μ™€ Address ν΄λž˜μŠ€κ°€ 있고, Member ν΄λž˜μŠ€μ—μ„œ Address 객체λ₯Ό ν•©μ„±(composition) ν•˜μ—¬ 가지고 μžˆλ‹€. 이 객체끼리 ν•©μ„±λœ 관계λ₯Ό ν•©μ„± ν•¨μˆ˜λ₯Ό 톡해 λ©€λ²„μ˜ λ„μ‹œ μ£Όμ†Œκ°’μ„ λΆˆλŸ¬μ˜€λŠ” κ°„λ‹¨ν•œ μ˜ˆμ œμ΄λ‹€.

class Member {
    private String name;
    private Address address; // Address 객체λ₯Ό ν•©μ„±(composition)

    public Member(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    public String getName() { return name; }

    public Address getAddress() { return address; }
}

class Address {
    private String country;
    private String city;

    public Address(String country, String city) {
        this.country = country;
        this.city = city;
    }

    public String getCountry() { return country; }

    public String getCity() { return city; }
}
public static void main(String[] args) {

    Member member = new Member("홍길동", new Address("μ‘°μ„ ", "ν•œμ–‘"));

    // Member λ§€κ°œνƒ€μž…κ³Ό Address λ¦¬ν„΄νƒ€μž…
    Function<Member, Address> f = x -> x.getAddress(); // Address 객체λ₯Ό μ–»κΈ°

    // Address λ§€κ°œνƒ€μž…κ³Ό String λ¦¬ν„΄νƒ€μž…
    Function<Address, String> g = x -> x.getCity(); // city λ¬Έμžμ—΄ μ–»κΈ°

    // f(g(x))
    Function<Member, String> fg = f.andThen(g);
    String city = fg.apply(member); // Address 객체λ₯Ό μ–»κ³ (f μ‹€ν–‰), Address κ°μ²΄μ—μ„œ city ν•„λ“œκ°’μ„ μ–»κΈ°(g μ‹€ν–‰)
    System.out.println("κ±°μ£Ό λ„μ‹œ : " + city);

    fg = g.compose(f);
    city = fg.apply(member);
    System.out.println("κ±°μ£Ό λ„μ‹œ : " + city);
}

Function ν•©μ„±


Predicate κ²°ν•©

Predicate ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” μ°Έ / 거짓 값을 λ¦¬ν„΄ν•˜λŠ” ν•¨μˆ˜λ₯Ό 닀룬닀. 즉, true / false 쑰건식에 λŒ€ν•˜μ—¬ 이듀을 κ²°ν•©ν•˜μ—¬ and μ—°μ‚°, or 연산을 ν–‰ν•œλ‹€κ³  보면 λœλ‹€. 

 μΈν„°νŽ˜μ΄μŠ€ λ©”μ†Œλ“œ μ„€λͺ…
default Predicate<T> and (Predicate<? super T> other)  and μ—°μ‚° 
default Predicate<T> or (Predicate<? super T> other) or μ—°μ‚°
default Predicate<T> negate() μ—­ λΆ€μ •
static <T> Predicate<T> isEqual(Object targetRef) 객체 비ꡐ

Predicate κ²°ν•©

 

λžŒλ‹€ κ²°ν•© μ‚¬μš© μ˜ˆμ‹œ

쑰건문을 κ΅¬μ„±ν• λ•Œ if(x > 10 && x < 20) μ΄λŸ°μ‹μœΌλ‘œ 쑰건 μ—°μ‚°μžλ₯Ό μ΄μš©ν•΄ λ²”μœ„λ₯Ό ꡬ성해본적이 μžˆμ„ 것이닀. 이것을 λžŒλ‹€ ν•¨μˆ˜λ‘œ ν‘œν˜„ν•œ 것이라고 보면 λœλ‹€.

public static void main(String[] args) {

    Predicate<Integer> greater = x -> x > 10;
    Predicate<Integer> less = x -> x < 20;

    // x > 10 && x < 20
    Predicate<Integer> between = greater.and(less); 
    System.out.println(between.test(15)); // true

    // x > 10 || x < 20
    Predicate<Integer> all = greater.or(less); 
    System.out.println(all.test(5)); // true

    // x <= 10
    Predicate<Integer> negate = greater.negate(); 
    System.out.println(negate.test(50)); // false
}

 

isEqual() 정적 μΈν„°νŽ˜μ΄μŠ€ λ©”μ†Œλ“œλŠ” μž…λ ₯κ°’μœΌλ‘œ 받은 객체와 같은지 νŒλ‹¨ν•΄μ£ΌλŠ” λ©”μ†Œλ“œ 이닀. κ·Έλƒ₯ equals() λ₯Ό λžŒλ‹€ ν•¨μˆ˜λ‘œ ν‘œν˜„ν•œ 것이라고 보면 λœλ‹€.

public static void main(String[] args) {
    // ν•¨μˆ˜μ˜ 인자둜 λ“€μ–΄μ˜¨ λ¬Έμžμ—΄μ΄ "홍길동" 인지 νŒλ³„ν•΄μ£ΌλŠ” ν•¨μˆ˜
    Predicate<String> checkMyName = Predicate.isEqual("홍길동");

    System.out.println(checkMyName.test("μž„κΊ½μ •")); // false
    System.out.println(checkMyName.test("홍길동")); // true
}

μžλ°” μ»¬λ ‰μ…˜μ˜ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

λ§ˆμ§€λ§‰μœΌλ‘œ μžλ°”μ˜ μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›Œν¬μ— ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ™€ ν•¨κ»˜ μ‚¬μš©ν•  수 μžˆλŠ” λ©”μ„œλ“œλ„ λ³„λ„λ‘œ μ§€μ›ν•œλ‹€.

collection-functional-interface

μΈν„°νŽ˜μ΄μŠ€ λ©”μ„œλ“œ μ„€λͺ…
Collection boolean removeIf(Predicate<E> filter); 쑰건에 λ§žλŠ” μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό μ‚­μ œ
List void replaceAll(UnaryOperator<E> operator); λͺ¨λ“  μ—˜λ¦¬λ¨ΌνŠΈμ— operatorλ₯Ό μ μš©ν•˜μ—¬ λŒ€μ²΄(replace)
Iterable void forEach(Consumer<T> action); λͺ¨λ“  μ—˜λ¦¬λ¨ΌνŠΈμ— action μˆ˜ν–‰
μΈν„°νŽ˜μ΄μŠ€ λ©”μ„œλ“œ μ„€λͺ…
Map V compute(K key, BiFunction<K, V, V> f); μ§€μ •λœ 킀에 ν•΄λ‹Ήν•˜λŠ” 값에 fλ₯Ό μˆ˜ν–‰
Map V computeIfAbsent(K key, Function<K, V> f); μ§€μ •λœ ν‚€κ°€ μ—†μœΌλ©΄ f μˆ˜ν–‰ν›„ μΆ”κ°€
Map V cumputeIfPresent(K key, BiFunction<K, V, V> f) μ§€μ •λœ ν‚€κ°€ μžˆμ„ λ•Œ, f μˆ˜ν–‰
Map V merge(K key, V value, BiFunction<V, V, V> f); λͺ¨λ“  μ—˜λ¦¬λ¨ΌνŠΈμ— Merge μž‘μ—… μˆ˜ν–‰, 킀에 ν•΄λ‹Ήν•˜λŠ” 값이 있으면 f μˆ˜ν–‰ν•΄μ„œ 병합후 ν• λ‹Ή
Map void forEach(BiConsumer<K, V> action); λͺ¨λ“  μ—˜λ¦¬λ¨ΌνŠΈμ— action μˆ˜ν–‰
Map void replaceAll(BiFunction<K, V, V> f); λͺ¨λ“  μ—˜λ¦¬λ¨ΌνŠΈμ— f μˆ˜ν–‰ν›„  λŒ€μ²΄
public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

    // 각 μš”μ†Œμ— 10을 곱함
    list.replaceAll( (x) -> x * 10 );

    // λ¦¬μŠ€νŠΈλŠ” Iteratble을 μƒμ†ν•˜λ‹ˆκΉŒ μ‚¬μš©μ΄ κ°€λŠ₯
    list.forEach( (x) -> System.out.println(x) );
}

collection-functional-interface


ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ API μ‚¬μš© μ •λ¦¬ν‘œ

λ³΄λ‹€μ‹œν”Ό ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μ’…λ₯˜λŠ” κ²°μ½” μ μ€κ²Œ μ•„λ‹ˆλΌ ν•˜λ‚˜ν•˜λ‚˜ κΈ°μ–΅ν•˜κΈ° μ• λ§€ν•˜κΈ°λ„ ν•˜κ³ , μ–Έμ œ μ–΄λŠλ•Œ μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μ„ 골라 μ‚¬μš©ν• μ§€ λ°”λ‘œ λ– μ˜¬λ¦¬κΈ°λ„ νž˜λ“€λ‹€. κ·Έλž˜μ„œ ν•œλˆˆμ— λ“€μ–΄μ˜¬ 수 있게 잘 μ •λ¦¬λœ 도식을 가져와 λ³΄μ•˜λ‹€.

μ™Όμͺ½ μ„Έλ‘œ 뢀뢄은 λ§€κ°œλ³€μˆ˜ νƒ€μž…μ„ λ‚˜νƒ€λ‚΄λŠ” 것이고, 각 ν‘œμ˜ μœ„μͺ½ 뢀뢄은 ν•¨μˆ˜ λ°˜ν™˜ νƒ€μž…μ„ λ‚˜νƒ€λ‚΄λŠ” 것이닀. 만일 double ν˜• λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ•„ void 둜 ν–‰ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€κ°€ 무엇인지 찾으렀면, μ™Όμͺ½μ—μ„œ (double) → 을 μ°Ύκ³  ν‘œ μƒλ‹¨μ˜ → void λ₯Ό λ§€μΉ˜ν•΄λ³΄λ©΄ λ°”λ‘œ DoubleConsumer μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•œλ‹€λŠ” 것을 μ•Œ 수 있게 λœλ‹€.

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ API μ‚¬μš© μ •λ¦¬ν‘œ


# 참고자료

https://hbase.tistory.com/78

https://palpit.tistory.com/673 

http://blog.orfjackal.net/2014/07/java-8-functional-interface-naming-guide.html