Post

🦊 chap3. λžŒλ‹€ ν‘œν˜„μ‹

3.1 λžŒλ‹€λž€ 무엇인가?

λžŒλ‹€ ν‘œν˜„μ‹μ€ λ©”μ„œλ“œλ‘œ 전달할 수 μžˆλŠ” 읡λͺ… ν•¨μˆ˜λ₯Ό λ‹¨μˆœν™”ν•œ 것이닀.

이름은 μ—†μ§€λ§Œ, νŒŒλΌλ―Έν„° 리슀트, λ°”λ””, λ°˜ν™˜ ν˜•μ‹, λ°œμƒν•  수 μžˆλŠ” μ˜ˆμ™Έ λ¦¬μŠ€νŠΈλŠ” κ°€μ§ˆ 수 μžˆλ‹€.

  • 읡λͺ… : 이름이 μ—†κΈ° λ•Œλ¬Έμ— 읡λͺ…이닀.
  • ν•¨μˆ˜ : νŠΉμ • ν΄λž˜μŠ€μ— μ’…μ†λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— λ©”μ„œλ“œκ°€ μ•„λ‹Œ ν•¨μˆ˜λΌκ³  λΆ€λ₯Έλ‹€.
  • 전달 : λžŒλ‹€ ν‘œν˜„μ‹μ„ 인수둜 μ „λ‹¬ν•˜κ±°λ‚˜ λ³€μˆ˜λ‘œ μ €μž₯ν•  수 μžˆλ‹€.
  • κ°„κ²°μ„± : 읡λͺ… 클래슀처럼 λ§Žμ€ μžμ§ˆκ΅¬λ ˆν•œ μ½”λ“œλ₯Ό κ΅¬ν˜„ν•  ν•„μš”κ°€ μ—†λ‹€.

λžŒλ‹€λŠ” μ„Έ λΆ€λΆ„μœΌλ‘œ 이루어진닀

1
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
  • νŒŒλΌλ―Έν„° 리슀트 : (Apple a1, Apple a2)
  • ν™”μ‚΄ν‘œ : -> νŒŒλΌλ―Έν„° λ¦¬μŠ€νŠΈμ™€ λ°”λ””λ₯Ό κ΅¬λΆ„ν•œλ‹€
  • λžŒλ‹€ λ°”λ”” : a1.getWeight().compareTo(a2.getWeight());

λ‹€μŒμ€ μžλ°” 8μ—μ„œ μ§€μ›ν•˜λŠ” μœ νš¨ν•œ λžŒλ‹€ ν‘œν˜„μ‹ 5가지이닀.

1
2
3
4
5
6
7
8
9
10
11
12
(String s) -> s.length()

(Apple a) -> a.getWeight() > 150

(int x, int y) -> {
	System.out.println("Result:");
	System.out.println(x + y);
}

() -> 42

(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

μžλ°” μ„€κ³„μžλŠ” 이미 C#μ΄λ‚˜ 슀칼라 같은 λΉ„μŠ·ν•œ κΈ°λŠ₯을 가진 λ‹€λ₯Έ 언어와 λΉ„μŠ·ν•œ 문법을 μžλ°”μ— μ μš©ν•˜κΈ°λ‘œ ν–ˆλ‹€.

λ‹€μŒμ€ ν‘œν˜„μ‹ μŠ€νƒ€μΌ λžŒλ‹€μ΄λ‹€.

1
(parameters) -> expression

λ‹€μŒμ€ 블둝 μŠ€νƒ€μΌ λžŒλ‹€μ΄λ‹€.

1
(parameters) -> { statements; }

λ‹€μŒμ€ λžŒλ‹€μ˜ μ‚¬μš© μ˜ˆμ‹œμ΄λ‹€.

λΆˆλ¦¬μ–Έ ν‘œν˜„μ‹(List list) β†’ list.isEmpty()
객체 생성() β†’ new Apple(10)
κ°μ²΄μ—μ„œ μ†ŒλΉ„(Apple a) β†’ { System.out.println(a.getWeight()); }
κ°μ²΄μ—μ„œ 선택/μΆ”μΆœ(String s) β†’ s.length()
두 값을 μ‘°ν•©(int a, int b) β†’ a * b
두 객체 비ꡐ(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

3.2 어디에, μ–΄λ–»κ²Œ λžŒλ‹€λ₯Ό μ‚¬μš©ν• κΉŒ?

3.2.1 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

2μž₯μ—μ„œ λ§Œλ“  Predicate μΈν„°νŽ˜μ΄μŠ€λ‘œ ν•„ν„° λ©”μ„œλ“œλ₯Ό νŒŒλΌλ―Έν„°ν™” ν•  수 μžˆμ—ˆλ‹€.

λ°”λ‘œ Predicate κ°€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€.

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” μ •ν™•νžˆ ν•˜λ‚˜μ˜ 좔상 λ©”μ„œλ“œλ₯Ό μ§€μ •ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface Comparator<T> {
	int compare(T o1, T o2);
}

public interface Runnable {
	void run();
}

public interface ActionListener extends EventListener {
	void actionPerformed(ActionEvent e);
}

public interface CallableV> {
	V call() throws Exception;
}

public interface PrivilegedAction<T> {
	T run();
}

λžŒλ‹€ ν‘œν˜„μ‹μœΌλ‘œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ 좔상 λ©”μ„œλ“œ κ΅¬ν˜„μ„ 직접 전달할 수 μžˆλ‹€.

즉 전체 ν‘œν˜„μ‹μ„ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ‘œ μ·¨κΈ‰ν•  수 μžˆλ‹€.

3.2.2 ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ 좔상 λ©”μ„œλ“œ μ‹œκ·Έλ‹ˆμ²˜λŠ” λžŒλ‹€ ν‘œν˜„μ‹μ˜ μ‹œκ·Έλ‹ˆμ²˜λ₯Ό 가리킨닀.

λžŒλ‹€ ν‘œν˜„μ‹μ˜ μ‹œκ·Έλ‹ˆμ²˜λ₯Ό μ„œμˆ ν•˜λŠ” λ©”μ„œλ“œλ₯Ό ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°λΌκ³  λΆ€λ₯Έλ‹€.

@FunctionalInterface λŠ” 무엇인가?

μ΄λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μž„μ„ κ°€λ¦¬ν‚€λŠ” μ–΄λ…Έν…Œμ΄μ…˜μ΄λ‹€.

이λ₯Ό μ΄μš©ν•˜μ—¬ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ„ μ–Έν–ˆμ§€λ§Œ μ‹€μ œλ‘œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€κ°€ μ•„λ‹ˆλΌλ©΄ 컴파일 μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.

이 μ–΄λ…Έν…Œμ΄μ…˜μ΄ μžˆλŠ” μΈν„°νŽ˜μ΄μŠ€λŠ” 좔상 λ©”μ„œλ“œκ°€ 단 ν•œκ°œ μ—¬μ•Ό ν•œλ‹€.

3.3 λžŒλ‹€ ν™œμš© : μ‹€ν–‰ μ–΄λΌμš΄λ“œ νŒ¨ν„΄

DB 파일 μ²˜λ¦¬μ™€ 같은 μžμ› μ²˜λ¦¬λŠ” μˆœν™˜ νŒ¨ν„΄μœΌλ‘œ μžμ›μ„ μ—΄κ³  μ²˜λ¦¬ν•œ λ‹€μŒ μžμ›μ„ λ‹«λŠ” μˆœμ„œλ‘œ 이루어진닀.

즉 μ‹€μ œ μžμ›μ„ μ²˜λ¦¬ν•˜λŠ” μ½”λ“œλ₯Ό μ„€μ •κ³Ό 정리 두 과정이 λ‘˜λŸ¬μ‹ΈλŠ” ν˜•νƒœμ΄λ‹€.

이λ₯Ό μ‹€ν–‰ μ–΄λΌμš΄λ“œ νŒ¨ν„΄(Execute Around Pattern) 이라고 λΆ€λ₯Έλ‹€.

1
2
3
4
5
public String processFile() throws IOException {
	try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
		return br.readline();
	}
}

3.3.1 1단계 : λ™μž‘ νŒŒλΌλ―Έν„°ν™”λ₯Ό κΈ°μ–΅ν•˜λΌ

ν˜„μž¬ μ½”λ“œλŠ” ν•œ λ²ˆμ— ν•œ μ€„λ§Œ 읽을 수 μžˆλ‹€.

기쑴의 μ„€μ •, 정리 과정은 μž¬μ‚¬μš©ν•˜κ³  λ‚΄λΆ€ λ©”μ„œλ“œλ§Œ λ‹€λ₯Έ λ™μž‘μ„ μˆ˜ν–‰ν•˜λ„λ‘ ν•˜λ €λ©΄?

processFile 의 λ™μž‘μ„ νŒŒλΌλ―Έν„°ν™”ν•˜λ©΄ λœλ‹€.

λžŒλ‹€λ₯Ό μ΄μš©ν•˜λ©΄ λ©”μ„œλ“œμ— λ™μž‘μ„ 전달할 수 μžˆλ‹€.

λ§Œμ•½ ν•œ λ²ˆμ— 두 행을 읽게 λ§Œλ“œλ €λ©΄?

1
String result = processFile((BufferedReader br) -> br.readLine() + br.readLine());

3.3.2 2단계 : ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ΄μš©ν•΄μ„œ λ™μž‘ 전달

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μžλ¦¬μ— λžŒλ‹€λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

1
2
3
4
@FunctionalInterface
public interface BufferedReaderProcessor {
	String process(BufferedReader b) throws IOException;
}
1
2
3
public String processFile(BufferedReaderProcessor p) throws IOException {

}

3.3.3 3단계 : λ™μž‘ μ‹€ν–‰

λžŒλ‹€ ν‘œν˜„μ‹μœΌλ‘œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ 좔상 λ©”μ„œλ“œ κ΅¬ν˜„μ„ 직접 전달할 수 있으며 μ „λ‹¬λœ μ½”λ“œλŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ‘œ μ „λ‹¬λœ μ½”λ“œμ™€ 같은 λ°©μ‹μœΌλ‘œ μ²˜λ¦¬ν•œλ‹€.

1
2
3
4
5
public String processFile(BufferedReaderProcessor p) throws IOException {
	try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
		return p.process(br);
	}
}

3.3.4 4단계 : λžŒλ‹€ 전달

λ‹€μŒμ€ ν•œ 행을 μ²˜λ¦¬ν•˜λŠ” μ½”λ“œμ΄λ‹€.

1
String oneLine = processFile((BufferedReader br) -> br.readLine());

λ‹€μŒμ€ 두 행을 μ²˜λ¦¬ν•˜λŠ” μ½”λ“œμ΄λ‹€.

1
String oneLine = processFile((BufferedReader br) -> br.readLine() + br.readLine());

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

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ 좔상 λ©”μ„œλ“œ μ‹œκ·Έλ‹ˆμ²˜λ₯Ό ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°λΌκ³  ν•œλ‹€.

λ‹€μ–‘ν•œ λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‚¬μš©ν•˜λ €λ©΄ κ³΅ν†΅μ˜ ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°λ₯Ό κΈ°μˆ ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ 집합이 ν•„μš”ν•˜λ‹€.

이미 μžλ°” API λŠ” Comparable, Runnable, Callable λ“±μ˜ λ‹€μ–‘ν•œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν¬ν•¨ν•œλ‹€.

μžλ°” 8μ—μ„œλŠ” java.util.function νŒ¨ν‚€μ§€μ— μ—¬λŸ¬ μƒˆλ‘œμš΄ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ œκ³΅ν•œλ‹€.

3.4.1 Predicate

java.util.function.Predicate<T> μΈν„°νŽ˜μ΄μŠ€λŠ” test λΌλŠ” 좔상 λ©”μ„œλ“œλ₯Ό μ •μ˜ν•˜κ³ 

T ν˜•μ‹μ˜ 객체λ₯Ό 인수둜 λ°›μ•„ boolean 을 λ°˜ν™˜ν•œλ‹€.

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

3.4.2 Consumer

java.util.function.Predicate<T> μΈν„°νŽ˜μ΄μŠ€λŠ” T 객체λ₯Ό λ°›μ•„μ„œ void λ₯Ό λ°˜ν™˜ν•˜λŠ” accept λΌλŠ” 좔상 λ©”μ„œλ“œλ₯Ό μ •μ˜ν•œλ‹€.

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

3.4.3 Function

java.util.function.Function<T, R> μΈν„°νŽ˜μ΄μŠ€λŠ” T 객체λ₯Ό λ°›μ•„μ„œ R 객체λ₯Ό λ₯Ό λ°˜ν™˜ν•˜λŠ” apply λΌλŠ” 좔상 λ©”μ„œλ“œλ₯Ό μ •μ˜ν•œλ‹€.

μž…λ ₯을 좜λ ₯으둜 λ§€ν•‘ν•˜λŠ” λžŒλ‹€λ₯Ό μ •μ˜ν•  λ•Œ ν™œμš©ν•  수 μžˆλ‹€.

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

μ œλ„€λ¦­ νŒŒλΌλ―Έν„°λŠ” μ°Έμ‘°ν˜•(Reference Type) 만 μ‚¬μš©ν•  수 μžˆλ‹€.

μžλ°”μ—μ„œλŠ” κΈ°λ³Έν˜•κ³Ό μ°Έμ‘°ν˜•μ„ λ³€ν™˜ν•˜λŠ” λ°•μ‹±, 언박싱을 μ§€μ›ν•œλ‹€.

이 λ™μž‘μ΄ μžλ™μœΌλ‘œ μ΄λ£¨μ–΄μ§€λŠ” μ˜€ν†  λ°•μ‹±μ΄λΌλŠ” κΈ°λŠ₯도 μ§€μ›ν•œλ‹€.

ν•˜μ§€λ§Œ 이런 λ³€ν™˜ 과정은 λΉ„μš©μ΄ μ†Œλͺ¨λœλ‹€.

λ°•μ‹±ν•œ 값은 κΈ°λ³Έν˜•μ„ κ°μ‹ΈλŠ” Wrapper 이고 νž™μ— μ €μž₯λœλ‹€.

μžλ°” 8μ—μ„œλŠ” κΈ°λ³Έν˜•μ„ μž…μΆœλ ₯으둜 μ‚¬μš©ν•˜λŠ” μƒν™©μ—μ„œ μ˜€ν† λ°•μ‹± λ™μž‘μ„ ν”Όν•  수 μžˆλ„λ‘ νŠΉλ³„ν•œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ œκ³΅ν•œλ‹€.

λ‹€μŒ μ˜ˆμ œμ—μ„œ IntPredicate λŠ” 1000 μ΄λΌλŠ” 값을 λ°•μ‹±ν•˜μ§€ μ•Šμ§€λ§Œ, Predicate λŠ” 1000μ΄λΌλŠ” 값을 Integer 객체둜 λ°•μ‹±ν•œλ‹€.

1
2
3
4
5
6
7
8
9
public interface IntPredicate {
	boolean test(int t);
}

IntPredicate evenNubmers = (int i) -> i % 2 == 0;
evenNumbers.test(1000);

Predicate<Integer> oddNumbers = (Integer i) -> i % 2 != 0;
oddNumbers.test(1000);

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” ν™•μΈλœ μ˜ˆμ™Έ (Checked Exception)을 λ˜μ§€λŠ” λ™μž‘μ„ ν—ˆμš©ν•˜μ§€ μ•ŠλŠ”λ‹€.

즉 μ˜ˆμ™Έλ₯Ό λ˜μ§€λŠ” λžŒλ‹€ ν‘œν˜„μ‹μ„ λ§Œλ“€λ €λ©΄ ν™•μΈλœ μ˜ˆμ™Έλ₯Ό μ„ μ–Έν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό 직접 μ •μ˜ν•˜κ±°λ‚˜ λžŒλ‹€λ₯Ό try/catch λΈ”λ‘μœΌλ‘œ 감싸야 ν•œλ‹€.

예λ₯Ό λ“€μ–΄ Function<T, R> ν˜•μ‹μ˜ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό κΈ°λŒ€ν•˜λŠ” APIλ₯Ό μ‚¬μš©ν•˜κ³  μžˆμ–΄ 직접 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ§Œλ“€κΈ° μ–΄λ ΅λ‹€λ©΄,

1
2
3
4
5
6
7
Function<BufferedReader, String> f = (BufferedReader b) -> {
	try {
		return b.readLine();
	} catch (IOException e) {
		throw new RuntimeException(e);
	}
}

비검사 μ˜ˆμ™Έλ‘œ μ „ν™˜ν•˜μ—¬μ•Ό ν•œλ‹€.

3.5 ν˜•μ‹ 검사, ν˜•μ‹ μΆ”λ‘ , μ œμ•½

λžŒλ‹€ ν‘œν˜„μ‹μ„ 더 μ œλŒ€λ‘œ μ΄ν•΄ν•˜λ €λ©΄ λžŒλ‹€μ˜ μ‹€μ œ ν˜•μ‹μ„ νŒŒμ•…ν•΄μ•Ό ν•œλ‹€.

3.5.1 ν˜•μ‹ 검사

λžŒλ‹€κ°€ μ‚¬μš©λ˜λŠ” context λ₯Ό μ΄μš©ν•΄μ„œ λžŒλ‹€μ˜ type 을 μΆ”λ‘ ν•  수 μžˆλ‹€.

μ–΄λ–€ context μ—μ„œ κΈ°λŒ€λ˜λŠ” λžŒλ‹€ ν‘œν˜„μ‹μ˜ ν˜•μ‹μ„ λŒ€μƒ ν˜•μ‹(target type)이라고 λΆ€λ₯Έλ‹€.

3.5.2 같은 λžŒλ‹€, λ‹€λ₯Έ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

λŒ€μƒ ν˜•μ‹μ΄λΌλŠ” νŠΉμ§•μœΌλ‘œ 같은 λžŒλ‹€ ν‘œν˜„μ‹μ΄λΌλ„ ν˜Έν™˜λ˜λŠ” 좔상 λ©”μ„œλ“œλ₯Ό 가진 λ‹€λ₯Έ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ‘œ μ‚¬μš©λ  수 μžˆλ‹€.

λ‹€μŒ 두 할당문은 λͺ¨λ‘ μœ νš¨ν•˜λ‹€.

1
2
Callable<Integer> c = () -> 42;
PrivilegedAction<Integer> p = () -> 42;

3.5.3 ν˜•μ‹ μΆ”λ‘ 

μžλ°” μ»΄νŒŒμΌλŸ¬λŠ” λŒ€μƒ ν˜•μ‹μ„ μ΄μš©ν•΄μ„œ ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°λ₯Ό μ•Œ 수 있기 λ•Œλ¬Έμ— μ»΄νŒŒμΌλŸ¬κ°€ λžŒλ‹€μ˜ μ‹œκ·Έλ‹ˆμ²˜λ„ μΆ”λ‘ ν•  수 μžˆλ‹€.

μ»΄νŒŒμΌλŸ¬κ°€ λžŒλ‹€ ν‘œν˜„μ‹μ˜ νŒŒλΌλ―Έν„° νƒ€μž…μ— μ ‘κ·Όν•  수 있기 λ•Œλ¬Έμ— λžŒλ‹€ λ¬Έλ²•μ—μ„œλŠ” 이λ₯Ό μƒλž΅ν•  수 μžˆλ‹€.

1
List<Apple> greenApples = filter(inventory, apple -> GREEN.equals(apple.getColor()));
1
2
3
4
5
6
7
// ν˜•μ‹ μΆ”λ‘  x
Comparator<Apple> c = 
	(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

// ν˜•μ‹ μΆ”λ‘ 
Comparator<Apple> c = 
	(a1, a2) -> a1.getWeight().compareTo(a2.getWeight());

3.5.4 지역 λ³€μˆ˜ μ‚¬μš©

λžŒλ‹€ ν‘œν˜„μ‹μ—μ„œλŠ” 읡λͺ… ν•¨μˆ˜μ²˜λŸΌ 자유 λ³€μˆ˜λ₯Ό ν™œμš©ν•  수 있고 이λ₯Ό λžŒλ‹€ 캑처링이라고 λΆ€λ₯Έλ‹€.

1
2
int portNumber = 1337;
Runnable r = () -> System.out.println(portNumber);

이λ₯Ό μœ„ν•΄μ„œλŠ” 지역 λ³€μˆ˜λŠ” λͺ…μ‹œμ μœΌλ‘œ final 둜 μ„ μ–Έλ˜κ±°λ‚˜ μž¬ν• λ‹Ήμ΄ 이루어지면 μ•ˆλœλ‹€.

λ‹€μŒμ€ μ»΄νŒŒμΌν•  수 μ—†λ‹€.

1
2
3
int portNumber = 1337;
Runnable r = () -> System.out.println(portNumber);
portNumber = 31337;

μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λŠ” νž™μ— μ €μž₯λ˜λŠ” 반면 지역 λ³€μˆ˜λŠ” μŠ€νƒμ— μœ„μΉ˜ν•œλ‹€.

κ·Έλ ‡κΈ° λ•Œλ¬Έμ— μžλ°” κ΅¬ν˜„μ—μ„œλŠ” μ›λž˜ λ³€μˆ˜μ— 접근을 ν—ˆμš©ν•˜λŠ”κ²Œ μ•„λ‹ˆλΌ

자유 지역 λ³€μˆ˜μ˜ 볡사본을 μ œκ³΅ν•œλ‹€.

λ”°λΌμ„œ λ³΅μ‚¬λ³Έμ˜ 값이 λ°”λ€Œμ§€ μ•Šμ•„μ•Ό ν•œλ‹€.

3.6 λ©”μ„œλ“œ μ°Έμ‘°

λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό μ΄μš©ν•˜λ©΄ 기쑴의 λ©”μ„œλ“œ μ •μ˜λ₯Ό μž¬ν™œμš©ν•΄μ„œ λžŒλ‹€μ²˜λŸΌ 전달할 수 μžˆλ‹€.

λ‹€μŒμ€ κΈ°μ‘΄ μ½”λ“œλ‹€.

1
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));

λ‹€μŒμ€ λ©”μ„œλ“œ 참쑰와 java.util.Comparator.comparing 을 ν™œμš©ν•œ μ½”λ“œλ‹€.

1
inventory.sort(comparing(Apple::getWeight));

3.6.1 μš”μ•½

λ©”μ„œλ“œ μ°Έμ‘°λŠ” νŠΉμ • λ©”μ„œλ“œλ§Œμ„ ν˜ΈμΆœν•˜λŠ” λžŒλ‹€μ˜ μΆ•μ•½ν˜•μ΄λΌ ν•  수 μžˆλ‹€.

λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό μ΄μš©ν•˜λ©΄ κΈ°μ‘΄ λ©”μ„œλ“œ κ΅¬ν˜„μœΌλ‘œ λžŒλ‹€ ν‘œν˜„μ‹μ„ λ§Œλ“€ 수 있고, λͺ…μ‹œμ μœΌλ‘œ λ©”μ„œλ“œλͺ…을 μ°Έμ‘°ν•¨μœΌλ‘œμ¨ 가독성을 높일 수 μžˆλ‹€.

λ©”μ„œλ“œ μ°Έμ‘°λŠ” μ„Έ 가지 μœ ν˜•μœΌλ‘œ ꡬ뢄할 수 μžˆλ‹€.

  1. 정적 λ©”μ„œλ“œ μ°Έμ‘°

Integer 의 parseInt λŠ” Integer::parseInt 둜 ν‘œν˜„ν•  수 μžˆλ‹€.

  1. λ‹€μ–‘ν•œ ν˜•μ‹μ˜ μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œ μ°Έμ‘°

String 의 length λŠ” String::length 둜 ν‘œν˜„ν•  수 μžˆλ‹€.

  1. κΈ°μ‘΄ 객체의 μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œ μ°Έμ‘°

Transaction 객체λ₯Ό 할당받은 expensiveTransaction 지역 λ³€μˆ˜ μΈμŠ€ν„΄μŠ€μ—μ„œ Transaction 객체의 getValue λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ expensiveTransaction::getValue 둜 ν‘œν˜„ν•  수 μžˆλ‹€.

3.6.2 μƒμ„±μž μ°Έμ‘°

ClassName::new 처럼 클래슀λͺ…κ³Ό new ν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•΄μ„œ κΈ°μ‘΄ μƒμ„±μžμ˜ μ°Έμ‘°λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

μΈμˆ˜κ°€ μ—†λŠ” μƒμ„±μžλŠ” Supplier λ₯Ό μ΄μš©ν•  수 μžˆλ‹€.

1
2
Supplier<Apple> c1 = Apple::new;
Apple a1 = c1.get();

Apple(Integer weight) λΌλŠ” μ‹œκ·Έλ‹ˆμ²˜λ₯Ό κ°–λŠ” μƒμ„±μžλŠ” Function 을 μ΄μš©ν•  수 μžˆλ‹€.

1
2
Fuction<Integer, Apple> c1 = Apple::new;
Apple a2 = c2.apply(110);

Apple(String color, Integer weight 처럼 두 인수λ₯Ό κ°–λŠ” μƒμ„±μžλŠ” BiFunction 을 μ΄μš©ν•œλ‹€.

1
2
Fuction<Color, Integer, Apple> c1 = Apple::new;
Apple a2 = c2.apply(GREEN, 110);

이λ₯Ό μ΄μš©ν•˜μ—¬ Map 으둜 μƒμ„±μžμ™€ λ¬Έμžμ—΄κ°’μ„ κ΄€λ ¨μ‹œν‚€κ³ , String, Integer κ°€ μ£Όμ–΄μ‘Œμ„ λ•Œ λ‹€μ–‘ν•œ 무게λ₯Ό κ°–λŠ” μ—¬λŸ¬ μ’…λ₯˜μ˜ 과일을 λ§Œλ“œλŠ” λ©”μ„œλ“œλ₯Ό μ •μ˜ν•  수 μžˆλ‹€.

1
2
3
4
5
6
7
8
9
10
static Map<Sring, Function<Integer, Fruit>> map = new HashMap<>();
static {
	map.put("apple", Apple::new);
	map.put("orange", Orange::new);
}

public static Fruit giveMeFruit(String fruit, Integer weight) {
	return map.get(fruit.toLowerCase()) // Function λ°˜ν™˜
						.apply(weight);
}

3.7 λžŒλ‹€, λ©”μ„œλ“œ μ°Έμ‘° ν™œμš©ν•˜κΈ°

3.7.1 1단계 : μ½”λ“œ 전달

1
void sort(Comparator<? super E> c)

이 μ½”λ“œλŠ” Comparator 객체λ₯Ό 인수둜 λ°›μ•„ 두 사과λ₯Ό λΉ„κ΅ν•œλ‹€.

객체 μ•ˆμ— λ™μž‘μ„ ν¬ν•¨μ‹œν‚€λŠ” λ°©μ‹μœΌλ‘œ 이제 sort 의 λ™μž‘μ€ νŒŒλΌλ―Έν„°ν™” λ˜μ—ˆλ‹€κ³  ν•  수 μžˆλ‹€.

1
2
3
4
5
6
public class AppleComparator implements Comparator<Apple> {
	public int compare(Apple a1, Apple a2) {
		return a1.getWeight().compareTo(a2.getWeight());
	}
}
inventory.sort(new AppleComparator());

3.7.2 2단계 : 읡λͺ… 클래슀 μ‚¬μš©

ν•œ 번만 μ‚¬μš©ν•  Comparator λ₯Ό κ΅¬ν˜„ν•˜λŠ” 것 λ³΄λ‹€λŠ” 읡λͺ… 클래슀λ₯Ό μ΄μš©ν•˜μž.

1
2
3
4
5
inventory.sort(new Comparator<Apple>() {
	public int compare(Apple a1, Apple a2) {
		return a1.getWeight().compareTo(a2.getWeight());
	}
}

3.7.3 3단계 : λžŒλ‹€ ν‘œν˜„μ‹ μ‚¬μš©

μžλ°” 8μ—μ„œλŠ” λžŒλ‹€ ν‘œν˜„μ‹μ΄λΌλŠ” κ²½λŸ‰ν™”λœ 문법을 μ‚¬μš©ν•΄ μ½”λ“œλ₯Ό 전달할 수 μžˆλ‹€.

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό κΈ°λŒ€ν•˜λŠ” κ³³ μ–΄λ””μ—μ„œλ‚˜ λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‚¬μš©ν•  수 μžˆλ‹€.

1
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));

μžλ°” μ»΄νŒŒμΌλŸ¬λŠ” λžŒλ‹€ ν‘œν˜„μ‹μ΄ μ‚¬μš©λœ context λ₯Ό μ‚¬μš©ν•΄μ„œ λžŒλ‹€μ˜ νŒŒλΌλ―Έν„° type 을 μΆ”λ‘ ν•œλ‹€.

1
inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));

Comparator λŠ” Comparable ν‚€λ₯Ό μΆ”μΆœν•΄μ„œ Comparator 객체둜 λ§Œλ“œλŠ” Function<> 을 인수둜 λ°›λŠ” 정적 λ©”μ„œλ“œ comparing 을 ν¬ν•¨ν•œλ‹€. 이λ₯Ό μ΄μš©ν•΄ 가독성을 ν–₯μƒν•˜μž

1
2
3
import static java.util.Comparator.comparing;

inventory.sort(comparing(apple -> apple.getWeight()));

3.7.4 4단계 : λ©”μ„œλ“œ μ°Έμ‘° μ‚¬μš©

λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό μ΄μš©ν•˜λ©΄ λžŒλ‹€ ν‘œν˜„μ‹œμ˜ 인수λ₯Ό 더 κΉ”λ”ν•˜κ²Œ 전달할 수 μžˆλ‹€.

1
inventory.sort(comparing(Apple::getWeight));

3.8 λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‘°ν•©ν•  수 μžˆλŠ” μœ μš©ν•œ λ©”μ„œλ“œ

μžλ°” 8 API의 λͺ‡λͺ‡ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” λ‹€μ–‘ν•œ μœ ν‹Έλ¦¬ν‹° λ©”μ„œλ“œλ₯Ό ν¬ν•¨ν•œλ‹€.

κ°„λ‹¨ν•œ μ—¬λŸ¬ 개의 λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‘°ν•©ν•˜μ—¬ λ³΅μž‘ν•œ λžŒλ‹€ ν‘œν˜„μ‹μ„ λ§Œλ“€ 수 μžˆλ‹€.

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ—μ„œ μΆ”κ°€λ‘œ λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•œλ‹€λŠ” 것 μžμ²΄κ°€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μ •μ˜μ— μ–΄κΈ‹λ‚˜λŠ” 것인데 μ–΄λ–»κ²Œ κ°€λŠ₯ν• κΉŒ?

λ°”λ‘œ λ””ν΄νŠΈ λ©”μ„œλ“œμ΄λ‹€.

3.8.1 Comparator μ‘°ν•©

1
Comparator<Apple> c = Comparator.comparing(Apple::getWeight);
  • μ—­μ •λ ¬

μ‚¬κ³Όμ˜ 무게λ₯Ό λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ μ •λ ¬ν•˜κ³  μ‹Άλ‹€λ©΄ reversed λ₯Ό μ‚¬μš©ν•œλ‹€

1
inventory.sort(comparing(Apple::getWeight).reversed());
  • μ—°κ²°

비ꡐ κ²°κ³Όλ₯Ό 더 닀듬을 수 μžˆλŠ” 두 번째 Comparatorλ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

thenComparing 은 첫 번째 λΉ„κ΅μžμ—μ„œ 두 객체가 κ°™λ‹€κ³  νŒλ‹¨λ˜λ©΄ 두 번째 λΉ„κ΅μžμ— 객체λ₯Ό μ „λ‹¬ν•œλ‹€.

1
2
3
inventory.sort(comparing(Apple::getWeight)
				.reversed()
				.thenComparing(Apple::getCountry));

3.8.2 Predicate μ‘°ν•©

  • λ°˜μ „

νŠΉμ • Predicate 의 κ²°κ³Όλ₯Ό λ°˜μ „μ‹œν‚¬ λ•Œ negate λ₯Ό μ‚¬μš©ν•œλ‹€.

1
Predicate<Apple> notRedApple = redApple.negate();
  • and

두 λžŒλ‹€λ₯Ό μ‘°ν•©ν•  λ•Œ and λ₯Ό μ‚¬μš©ν•œλ‹€.

1
Predicate<Apple> redAndHeavyApple = redApple.and(apple -> apple.getWeight() > 150);
  • or

두 λžŒλ‹€λ₯Ό μ‘°ν•©ν•  λ•Œ or 을 μ‚¬μš©ν•œλ‹€.

1
2
3
Predicate<Apple> redAndHeavyAppleOrGreen = 
		redApple.and(apple -> apple.getWeight() > 150);
						.or(apple -> GREEN.equals(a.getColor()));

3.8.3 Function μ‘°ν•©

  • andThen

주어진 ν•¨μˆ˜λ₯Ό λ¨Όμ € μ μš©ν•œ κ²°κ³Όλ₯Ό λ‹€λ₯Έ ν•¨μˆ˜μ˜ μž…λ ₯으둜 μ „λ‹¬ν•œλ‹€.

1
2
3
4
Function<Integer, Integer> f = x -> x + 1;
Function<Integer, Integer> g = x -> x * 2;
Function<Integer, Integer> h = f.andThen(g); // μˆ˜ν•™μ μœΌλ‘œ g(f(x))
int result = h.apply(1); // 4λ₯Ό λ°˜ν™˜
  • compose

인수둜 주어진 ν•¨μˆ˜λ₯Ό λ¨Όμ € μ‹€ν–‰ν•˜κ³  μ™ΈλΆ€ ν•¨μˆ˜μ— κ²°κ³Όλ₯Ό μ „λ‹¬ν•œλ‹€.

1
2
3
4
Function<Integer, Integer> f = x -> x + 1;
Function<Integer, Integer> g = x -> x * 2;
Function<Integer, Integer> h = f.compose(g); // μˆ˜ν•™μ μœΌλ‘œ f(g(x))
int result = h.apply(1); // 3을 λ°˜ν™˜
This post is licensed under CC BY 4.0 by the author.