λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

Dev Book Review/Java8 in Action

[μžλ°”8μΈμ•‘μ…˜] Chap.3 λžŒλ‹€ ν‘œν˜„μ‹

μ†ŒμŠ€μ½”λ“œ

https://github.com/mjung1798/Jyami-Java-Lab/tree/master/java8-in-action

 

mjung1798/Jyami-Java-Lab

πŸ’» Jyami의 Spring boot 및 Java μ‹€ν—˜μ†Œ πŸ’». Contribute to mjung1798/Jyami-Java-Lab development by creating an account on GitHub.

github.com

λ™μž‘ νŒŒλΌλ―Έν„°ν™” : λ³€ν™”ν•˜λŠ” μš”κ΅¬μ‚¬ν•­μ— 효과적으둜 λŒ€μ‘ν•  수 μžˆλŠ” μ½”λ“œ

  • 읡λͺ… 클래슀 : λ‹€μ–‘ν•œ λ™μž‘ κ΅¬ν˜„ κ°€λŠ₯ -> μ½”λ“œκ°€ κΉ”λ”ν•˜μ§€ μ•Šλ‹€
  • λžŒλ‹€ ν‘œν˜„μ‹ : 더 κΉ”λ”ν•œ μ½”λ“œλ‘œ λ™μž‘μ„ κ΅¬ν˜„ν•  수 μžˆλ‹€.

 

1. λžŒλ‹€λž€ 무엇인가

a. λžŒλ‹€μ˜ νŠΉμ§•

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

b. λžŒλ‹€μ˜ ꡬ성

Comparator<Apple> byWeight = (Apple a1, Apple a2) -> a1.getWeight.compareTo(a2.getWeight);
  • νŒŒλΌλ―Έν„° 리슀트 : Comparator의 compare λ©”μ„œλ“œμ˜ νŒŒλΌλ―Έν„° (두 개의 사과)
  • ν™”μ‚΄ν‘œ : λžŒλ‹€μ˜ νŒŒλΌλ―Έν„° λ¦¬μŠ€νŠΈμ™€ λ°”λ””λ₯Ό ꡬ뢄
  • λžŒλ‹€μ˜ λ°”λ”” : 두 μ‚¬κ³Όμ˜ 무게λ₯Ό λΉ„κ΅ν•œλ‹€. λžŒλ‹€μ˜ λ°˜ν™˜κ°’μ— ν•΄λ‹Ήν•˜λŠ” ν‘œν˜„μ‹

c. λžŒλ‹€ 예제

μ‚¬μš© 사둀 λžŒλ‹€ 예제
뢈린 ν‘œν˜„μ‹ (List<String> 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);

 

2. λžŒλ‹€λ₯Ό μ‚¬μš©ν•˜λŠ” κ³³

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ λ¬Έλ§₯μ—μ„œ μ‚¬μš©

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

  • μ •ν™•νžˆ ν•˜λ‚˜μ˜ μΆ”μƒλ©”μ„œλ“œλ₯Ό μ§€μ •ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€
  • λ§Žμ€ λ””ν΄νŠΈ λ©”μ„œλ“œκ°€ μžˆλ”λΌλ„ 좔상 λ©”μ„œλ“œκ°€ 였직 ν•˜λ‚˜λ©΄ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

ex ) Comprator, Runnable

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

@FunationalInterface : ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μž„μ„ κ°€λ¦¬ν‚€λŠ” μ–΄λ…Έν…Œμ΄μ…˜, 이λ₯Ό μ„ μ–Έν•˜κ³  μ‹€μ œλ‘œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€κ°€ μ•„λ‹ˆλ©΄ 컴파일 μ—λŸ¬ λ°œμƒ

b. ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°(function descriptor)

λžŒλ‹€ ν‘œν˜„μ‹μ˜ μ‹œκ·Έλ„ˆμ²˜λ₯Ό μ„œμˆ ν•˜λŠ” λ©”μ„œλ“œ

() -> void : νŒŒλΌλ―Έν„° λ¦¬μŠ€νŠΈκ°€ μ—†μœΌλ©° void λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜ : Runnable

(Apple, Apple) -> int : λ‘κ°œμ˜ Apple을 인수둜 λ°›μ•„ intλ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜

c. μ‚¬μš©λ²•

  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό 인수둜 λ°›λŠ” λ©”μ„œλ“œλ‘œ 전달
  • λ³€μˆ˜μ— ν• λ‹Ή

 

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

μ‹€ν–‰ μ–΄λΌμš΄λ“œ νŒ¨ν„΄(execute around pattern) : μžμ›μ„ μ—΄κ³  -> μ²˜λ¦¬ν•œ λ‹€μŒ(변동) -> μžμ›μ„ λ‹«λŠ”λ‹€

// μžμ› μ—΄κ³  λ‹«λŠ” 둜직이 μ€‘λ³΅μ μœΌλ‘œ μ•žλ’€μ— μžˆλ‹€.
public static String processFile2(BufferedReaderProcessor p) throws IOException {
  InputStream fileResourceAsStream = FileProcessor.class.getClassLoader().getResourceAsStream("data.txt");
  try(BufferedReader br = new BufferedReader(new InputStreamReader(fileResourceAsStream))){
    return p.process(br);
  }
}

//처리 λ‘œμ§μ— λŒ€ν•œ λ™μž‘μ„ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ΄μš©ν•΄ νŒŒλΌλ―Έν„°ν™” ν•˜μ˜€λ‹€.
@FunctionalInterface
public interface BufferedReaderProcessor {
  String process(BufferedReader br) throws IOException;
}

// 처리 λ‘œμ§μ— λŒ€ν•œ λ™μž‘μ„ μ„ μ–Έν•˜μ—¬, μ‹€ν–‰ μ–΄λΌμš΄λ“œ νŒ¨ν„΄μ•ˆμ—μ„œ ν•΄λ‹Ή λ™μž‘μ„ μˆ˜ν–‰ν•œλ‹€.
@Test
@DisplayName("μ‹€ν–‰ μ–΄λΌμš΄λ“œ νŒ¨ν„΄ κ°œμ„ 1")
void name2() throws IOException {
  String s = FileProcessor.processFile2(br -> br.readLine());
  assertThat(s).isEqualTo("line1");
}

 

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

ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°(function descriptor) : ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ 좔상 λ©”μ„œλ“œ μ‹œκ·Έλ„ˆμ²˜

κ³΅ν†΅μ˜ ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°λ₯Ό κΈ°μˆ ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ 집합 : Comparable, Runnable, Callable λ“± μžλ°”μ—μ„œ ν¬ν•¨ν•˜κ³  μžˆλ‹€

a. Predicate

Predicate<String> lengthOnePredicate = (String s) -> s.length() == 1;
List<String> filter = PredicateProcess.filter(list, lengthOnePredicate);
  • Input : μ œλ„€λ¦­ ν˜•μ‹ T 객체
  • Output : Boolean λ°˜ν™˜

b. Consumer

Consumer<Integer> printConsumer = i -> System.out.println(i);
ConsumerProcess.forEach(list, printConsumer);
  • Input : μ œλ„€λ¦­ ν˜•μ‹ T 객체
  • Output : void λ°˜ν™˜

c. Function

Function<String, Integer> parseIntegerFunction = s -> Integer.parseInt(s);
List<Integer> map = FunctionProcess.map(list, parseIntegerFunction);
  • Input : μ œλ„€λ¦­ ν˜•μ‹ T 객체
  • Output : μ œλ„€λ¦­ ν˜•μ‹ R 객체

d. κΈ°λ³Έν˜• νŠΉν™”

  • λ°•μ‹±(boxing) : κΈ°λ³Έν˜• -> μ°Έμ‘°ν˜• λ³€ν™˜
  • μ–Έλ°•μ‹±(unboxing) : μ°Έμ‘°ν˜• -> κΈ°λ³Έν˜• λ³€ν™˜
  • μ˜€ν† λ°•μ‹±(autoboxing) : λ°•μ‹±κ³Ό 언박싱이 μžλ™μœΌλ‘œ 이루어짐

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

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„° κΈ°λ³Έν˜• νŠΉν™”
Predicate<T> T -> boolean IntPredicate, LongPredicate, DoublePredicate
Consumer<T> T -> void IntConsumer, LongConsumer, DoubleConsumer
Function<T,R> T -> R IntFunction, IntToDoubleFunction, IntToLongFunction, LongFunction, LongToDoubleFunction, LongToIntFunction, DoubleFunction, ToIntFunction, ToDoubleFunction, ToLongFunction
Supplier<T> () -> T BooleanSupplier, IntSupplier, LongSupplier, DoubleSupplier
UnaryOperator<T> T -> T IntUnaryOperator, LongUnaryOperator, DoubleUnaryOperator
BinaryOperator<T> (T, T) -> T IntBinaryOprator, LongBinaryOperator, DoubleBinaryOperator
BiPredicate<L,R> (L, R) -> boolean  
BiConsumer<T,U> (T, U) -> void ObjIntConsumer, ObjLongConsumer, ObjDoubleConsumer
BiFunction<T,U,R> () ToIntBiFunction<T,U>, ToLongBiFunction<T,U>, ToDoubleBiFunction<T,U>

 

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

a. ν˜•μ‹κ²€μ‚¬

λžŒλ‹€κ°€ μ‚¬μš©λ˜λŠ” μ»¨ν…μŠ€νŠΈλ₯Ό μ΄μš©ν•΄μ„œ λžŒλ‹€μ˜ ν˜•μ‹μ„ μΆ”λ‘ ν•  수 μžˆλ‹€.

λŒ€μƒν˜•μ‹ (target type) : μ–΄λ–€ μ»¨ν…μŠ€νŠΈμ—μ„œ κΈ°λŒ€λ˜λŠ” λžŒλ‹€ ν‘œν˜„μ‹μ˜ ν˜•μ‹

filter(inventory, (Apple a)->a.getWeight > 150);

1. λžŒλ‹€κ°€ μ‚¬μš©λœ μ»¨ν…μŠ€νŠΈν™•μΈ : filter의 μ •μ˜ 확인
2. 두 번째 νŒŒλΌλ―Έν„°λ‘œ Predicate<Apple> ν˜•μ‹(λŒ€μƒ ν˜•μ‹)을 κΈ°λŒ€ν•œλ‹€.
3. Predicate<Apple>의 μΆ”μƒλ©”μ„œλ“œλ₯Ό ν™•μΈν•œλ‹€.
4. Apple을 인수둜 λ°›μ•„ boolean을 λ°˜ν™˜ν•˜λŠ” test λ©”μ„œλ“œλ‹€ (Apple->boolean)
5. ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°μ™€, λžŒλ‹€μ˜ μ‹œκ·Έλ„ˆμ²˜κ°€ μΌμΉ˜ν•œλ‹€! : ν˜•μ‹κ²€μ‚¬ μ™„λ£Œ

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

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

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

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

c. ν˜•μ‹μΆ”λ‘ 

μžλ°” 컴파일러

  • λžŒλ‹€ ν‘œν˜„μ‹μ΄ μ‚¬μš©λœ μ»¨ν…μŠ€νŠΈ(λŒ€μƒ ν˜•μ‹) λ₯Ό μ΄μš©ν•΄ λžŒλ‹€ ν‘œν˜„μ‹κ³Ό κ΄€λ ¨λœ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μΆ”λ‘ 
  • λŒ€μƒ ν˜•μ‹μ„ μ΄μš©ν•΄μ„œ ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°λ₯Ό μ•Œ 수 μžˆλ‹€.
  • μ»΄νŒŒμΌλŸ¬λŠ” λžŒλ‹€μ˜ μ‹œκ·Έλ„ˆμ²˜λ„ μΆ”λ‘ ν•  수 μžˆλ‹€.

상황에 따라 λͺ…μ‹œμ μœΌλ‘œ ν˜•μ‹μ„ ν¬ν•¨ν•˜λŠ” 것이 쒋을 λ•Œλ„ 있고 ν˜•μ‹μ„ λ°°μ œν•˜λŠ” 것이 가독성을 ν–₯μƒμ‹œν‚¬ λ•Œλ„ μžˆλ‹€.

// ν˜•μ‹ 좔둠을 ν•˜μ§€ μ•ŠλŠ”λ‹€
Comparator<Apple> c = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());


// ν˜•μ‹ 좔둠을 ν•œλ‹€
Comparator<Apple> c = (a1, a2) -> a1.getWeight().compareTo(a2.getWeight());

d. μ§€μ—­λ³€μˆ˜ μ‚¬μš©

  • μžμœ λ³€μˆ˜(free variable) : νŒŒλΌλ―Έν„°λ‘œ λ„˜κ²¨μ§„ λ³€μˆ˜κ°€ μ•„λ‹Œ μ™ΈλΆ€μ—μ„œ μ •μ˜λœ λ³€μˆ˜ => λžŒλ‹€μΊ‘μ²˜λ§(capturing lambda)
  • μ œμ•½ : final둜 μ„ μ–Έλ˜μ–΄μžˆκ±°λ‚˜ μ‹€μ§ˆμ μœΌλ‘œ final둜 μ„ μ–Έλœ λ³€μˆ˜μ™€ λ˜‘κ°™μ΄ μ‚¬μš©λ˜μ–΄μ•Όν•œλ‹€.

λžŒλ‹€ ν‘œν˜„μ‹μ€ ν•œλ²ˆλ§Œ ν• λ‹Ήν•  수 μžˆλŠ” μ§€μ—­λ³€μˆ˜λ₯Ό μΊ‘μ³ν•œλ‹€.

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

μ œμ•½μ΄ μžˆλŠ” 이유

  • μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λŠ” νž™μ— μ €μž₯, μ§€μ—­λ³€μˆ˜λŠ” μŠ€νƒμ— μ €μž₯λœλ‹€.
  • λžŒλ‹€κ°€ μŠ€λ ˆλ“œμ—μ„œ μ‹€ν–‰λœλ‹€λ©΄ λ³€μˆ˜λ₯Ό ν• λ‹Ήν•œ μŠ€λ ˆλ“œκ°€ μ‚¬λΌμ Έμ„œ λ³€μˆ˜ 할당이 ν•΄μ œλ˜μ—ˆλŠ”λ°λ„ λžŒλ‹€λ₯Ό μ‹€ν–‰ν•˜λŠ” μŠ€λ ˆλ“œμ—μ„œ ν•΄λ‹Ή λ³€μˆ˜μ— μ ‘κ·Όν•˜λ € ν•  수 μžˆλ‹€.
  • μ›λž˜ λ³€μˆ˜μ— 접근을 ν—ˆμš©ν•˜μ§€ μ•Šκ³  자유 지역 λ³€μˆ˜μ˜ 볡사본을 μ œκ³΅ν•œλ‹€
  • λ³΅μ‚¬λ³Έμ˜ 값이 λ°”λ€Œμ§€ μ•Šμ•„μ•Όν•œλ‹€ == 지역 λ³€μˆ˜μ—λŠ” ν•œ 번만 값을 ν• λ‹Ήν•΄μ•Ό ν•œλ‹€.

e. ν΄λ‘œμ €

ν΄λ‘œμ € : ν•¨μˆ˜μ˜ 비지역 λ³€μˆ˜λ₯Ό 자유둭게 μ°Έμ‘°ν•  수 μžˆλŠ” ν•¨μˆ˜μ˜ μΈμŠ€ν„΄μŠ€

μ„€λͺ…! ν΄λ‘œμ € λžŒλ‹€
λ‹€λ₯Έν•¨μˆ˜μ˜ 인수둜 전달할 수 μžˆλ‹€. O O
μžμ‹ μ˜ μ™ΈλΆ€ μ˜μ—­μ˜ λ³€μˆ˜μ— μ ‘κ·Όν•  수 μžˆλ‹€. O O
λžŒλ‹€κ°€ μ •μ˜λœ λ©”μ„œλ“œμ˜ μ§€μ—­λ³€μˆ˜ 값을 λ°”κΏ€ 수 μžˆλ‹€. O X

 

6. λ©”μ„œλ“œ 레퍼런슀

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

λͺ…μ‹œμ μœΌλ‘œ λ©”μ„œλ“œλͺ…을 μ°Έμ‘°ν•˜μ—¬ 가독성을 높일 수 μžˆλ‹€! λ©”μ„œλ“œ λͺ… μ•žμ— κ΅¬λΆ„μž(::)λ₯Ό λΆ™μ΄λŠ” λ°©μ‹μœΌλ‘œ ν™œμš©ν•œλ‹€.

Apple ν΄λž˜μŠ€μ— μ •μ˜λœ getWeight λ©”μ„œλ“œ 레퍼런슀

  • Apple::getWeight
  • (Apple a)-> a.getWeight()

a. λ©”μ„œλ“œ 레퍼런슀λ₯Ό λ§Œλ“œλŠ” 방법

1. 정적 λ©”μ„œλ“œ 레퍼런슀

Function<String, Integer> stringIntegerFunctionLambda = (String str) -> Integer.parseInt(str);
Function<String, Integer> stringIntegerFunction = Integer::parseInt;

 

2. λ‹€μ–‘ν•œ ν˜•μ‹μ˜ μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œ 레퍼런슀

Function<String, Integer> stringIntegerFunctionLambda = (String arg0) -> arg0.length();
Function<String, Integer> stringIntegerFunction = String::length;

3. κΈ°μ‘΄ 객체의 μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œ 레퍼런슀

λžŒλ‹€ ν‘œν˜„μ‹μ— ν˜„μ‘΄ν•˜λŠ” μ™ΈλΆ€ 객체의 λ©”μ„œλ“œλ₯Ό 호좜 ν•  λ•Œ μ‚¬μš©

Apple apple = new Apple("red", 100);
Supplier<Integer> supplierLambda = () -> apple.getWeight();
Supplier<Integer> supplier = apple::getWeight;

λ©”μ„œλ“œ λ ˆνΌλŸ°μŠ€λŠ” μ»¨ν…μŠ€νŠΈμ˜ ν˜•μ‹κ³Ό μΌμΉ˜ν•˜λŠ”μ§€ ν™•μΈν•œλ‹€.

b. μƒμ„±μž 레퍼런슀

ClassName::new 처럼 ν΄λž˜μŠ€μ™€ new ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ κΈ°μ‘΄ μƒμ„±μžμ˜ 레퍼런슀λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

@Getter
public class Apple {
    private String color;
    private Integer weight;
    public Apple() {
    }
    public Apple(String color) {
        this.color = color;
    }
    public Apple(Integer weight) {
        this.weight = weight;
    }
    public Apple(String color, Integer weight) {
        this.color = color;
        this.weight = weight;
    }
}
// κΈ°λ³Έ μƒμ„±μž 레퍼런슀
Supplier<Apple> appleSupplier = Apple::new;

//인수 1개 μƒμ„±μž 레퍼런슀 : 무게
Function<Integer, Apple> appleFunction = Apple::new;

// 인수 1개 μƒμ„±μž 레퍼런슀 : 색깔
Function<String, Apple> appleFunction = Apple::new;

// 인수 2개 μƒμ„±μž 레퍼런슀
BiFunction<String, Integer, Apple> appleBiFunction = Apple::new;

μ‹œκ·Έλ„ˆμ²˜λ₯Ό λŒ€μ‘μ‹œμΌœμ„œ μƒμ„±μžμ— 접근이 κ°€λŠ₯ν•˜λ‹€.

 

7. λžŒλ‹€, λ©”μ„œλ“œ 레퍼런슀 정리

  • μ½”λ“œ 전달 : ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜μ—¬ μ‚¬μš©
  • 읡λͺ… 클래슀 μ‚¬μš© : 클래슀λ₯Ό κ΅¬ν˜„ν•˜μ§€ μ•Šκ³  λ°”λ‘œ μΈμŠ€ν„΄μŠ€ ν™” ν•  수 μžˆμœΌλ‚˜ μ½”λ“œκ°€ μ§€μ €λΆ„ν•˜λ‹€.
  • λžŒλ‹€ ν‘œν˜„μ‹ μ‚¬μš© : 좔상 λ©”μ„œλ“œμ˜ μ‹œκ·Έλ„ˆμ²˜(ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°)κ°€ λžŒλ‹€ ν‘œν˜„μ‹μ˜ μ‹œκ·Έλ„ˆμ²˜λ₯Ό μ •μ˜ν•œλ‹€ = ν˜•μ‹μΆ”λ‘ μ— 이용
  • λ©”μ„œλ“œ 레퍼런슀 ν™œμš© : λžŒλ‹€ ν‘œν˜„μ‹μ˜ 인수λ₯Ό 더 κΉ”λ”ν•˜κ²Œ 전달할 수 μžˆλ‹€.

 

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

λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‘°ν•©ν•  수 μžˆλŠ” μœ ν‹Έλ¦¬ν‹° λ©”μ„œλ“œ : λ””ν΄νŠΈλ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•œλ‹€

@FunctionalInterface
public interface Comparator<T> {
  int compare(T o1, T o2); // μΆ”μƒλ©”μ„œλ“œ
  default Comparator<T> reversed() {...}
  default Comparator<T> thenComparing(Comparator<? super T> other) {...}
}

μ‹€μ œλ‘œ μœ„μ™€ 같이 선언이 λ˜μ–΄μžˆλ‹€.

λ‹¨μˆœν•œ λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‘°ν•©ν•΄μ„œ 더 λ³΅μž‘ν•œ λžŒλ‹€ ν‘œν˜„μ‹μ„ λ§Œλ“€ 수 μžˆλ‹€.

a. Comparator μ‘°ν•©

inventory.sort(
  Comparator.comparing(Apple::getWeight)
  .reversed() // μ—­μ •λ ¬
  .thenComparing(Apple::getColor)); // λ‘λ²ˆμ§Έ λΉ„κ΅μžλ₯Ό λ§Œλ“€ 수 μžˆλ‹€ (두 사과 비ꡐ ν›„ 같을 λ•Œ μ •λ ¬ 법)

b. Predicate μ‘°ν•©

Predicate<Apple> redApple = a -> "red".equals(a.getWeight());
// κΈ°μ‘΄ Predicateλ₯Ό λ°˜μ „
Predicate<Apple> notRedApple = redApple.negate();
// κΈ°μ‘΄ Predicate에 andλ₯Ό μ΄μš©ν•΄μ„œ λΉ¨κ°•μ΄λ©΄μ„œ 무거운 μ‚¬κ³Όλ‘œ μ‘°ν•©
Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight() > 150);
// κΈ°μ‘΄ Predicate에 orλ₯Ό μ΄μš©ν•΄μ„œ λΉ¨κ°•μ΄λ©΄μ„œ 무거운 사과 λ˜λŠ” κ·Έλƒ₯ λ…Ήμƒ‰μ‚¬κ³Όλ‘œ μ‘°ν•©
Predicate<Apple> redAndHeavyAppleOrGreen = redApple
  .and(a -> a.getWeight() > 150)
  .or(a -> "green".equals(a.getColor()));

c. Function μ‘°ν•©

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

compose : 인수둜 주어진 ν•¨μˆ˜λ₯Ό λ¨Όμ € μ‹€ν–‰ ν•œ 후에 κ·Έ κ²°κ³Όλ₯Ό μ™ΈλΆ€ ν•¨μˆ˜μ˜ 인수둜 제곡

@Test
@DisplayName("Function μ—°κ²°")
void name3() {
  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);
  assertThat(result).isEqualTo(4);
}

@Test
@DisplayName("Function μ—°κ²°")
void name4() {
  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);
  assertThat(result).isEqualTo(3);
}