티스토리 뷰

● 도입

1. Scope(스코프 / 유효범위)

-  Scope : 변수에 접근할 수 있는 범위

 함수 안에 함수가 있을 때 내부 함수에서 외부 함수에 있는 변수에 접근이 가능하다.(lexical scope)

- 그 반대는 불가능

- 내부에 있는 Lambda가 다른 함수의 return 값이 되어도(다른 곳으로 넘어가더라도) 여전히 생성 당시의 상위 스코프에서 접근 가능했던 변수들에는 접근 가능하다. 이것을 lexical scope라고 한다.

- Lambda 안에서는 Lambda 밖에 있는 변수에 접근 가능하다. 그 반대는 불가능

public static Supplier<String> getStringSupplier() {
	String hello = "Hello";
	Supplier<String> supplier = () -> {
		String world = "World";
		return hello + world;
	};
	return supplier; // String을 return 하는 Supplier를 return
}

- 일반적으로 method는 호출이 끝나면 method 안에서 선언된 변수들은 사라진다.
- 하지만 return 된 supplier Lambda는 여전히 hello 라는 변수가 필요하다.
- getStringSupplier method를 호출한 후 return 된 supplier Lambda를 호출하면 어떻게 될까?
- supplier Lambda가 사용하는 외부 변수는 여전히 존재하며 문제 없이 사용할 수 있다.
--> 이때 사용되는 개념이 바로 'Closure' 이다.

 

2. Closure

- Closure : 내부 함수가 존재하는 한 내부 함수가 사용한 외부 함수의 변수들 역시 계속 존재한다.

- 이렇게 lexical scope를 포함하는 함수를 closure라 한다.
- 이 때 내부 함수가 사용한 외부 함수의 변수(위의 예에서는 hello 변수)들은 내부 함수 선언 당시로부터 변할 수 없기 때문에 final로 선언되지 않더라도 암묵적으로 final로 취급된다.

cf) hello 변수를 바꾸려고 하면 compile error 가 발생한다.

 

3. Curry

BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
=>
Function<Integer, Function<Integer, Integer>> add = x -> y -> x + y;

- x를 먼저 받은 후 나중에 y를 받아 최종적으로 (x + y)를 return
- Function<Integer, Function<Integer, Integer>>의 return 값으로 설정된 Function<Integer, Integer>은
return 되어 다른 곳으로 가더라도 여전히 x 값을 사용할 수 있다.(Closure 덕분)

- Closure의 개념을 응용한 것이다.

- 여러 개의 매개변수를 받는 함수를 더 적은 수의 매개 변수를 받는 여러 개의 중첩된 함수로 쪼개어 매개 변수를 한 번에 받지 않고 여러 단계에 걸쳐 나눠 받을 수 있게 하는 기술

 

● 실습

package com.fastcampus.functionalprogramming.chapter9;

import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

public class Chapter9Section1 {
	public static void main(String[] args) {
		// 1. Scope & Closure
		// getStringSupplier를 호출해 return 되는 supplier를 받았다.
		Supplier<String> supplier = getStringSupplier();
		
		// return 값으로 받은 supplier를 호출
		System.out.println(supplier.get());
		
		/*
		 * [결과값] = HelloWorld
		 * - 일반적으로 생각하면 getStringSupplier method의 호출이 끝났을 때 hello 변수는 사라져야 한다.
		 * - 하지만 return 된 supplier가 계속해서 hello 변수를 사용해야하기 때문에
		 * - System.out.println(supplier.get())를 호출하는 시점에도 hello 변수는 여전히 남아있는 것이다.
		 */
// ===================================================================================================
		// 2. Curry
		BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
		int result = add.apply(3, 10);
		System.out.println("result : " + result);
		
		// x를 먼저 받고 나중에 y를 받는 식으로 함수를 쪼개고 싶다.
		Function<Integer, Function<Integer, Integer>> curriedAdd = x -> y -> x + y;
		Function<Integer, Integer> addThree = curriedAdd.apply(3);
		int result2 = addThree.apply(10);
		System.out.println("result2 : " + result2);
		/*
		 * curriedAdd.apply(3)을 통해 Function을 return 받은 addThree 변수는
		 * 어디를 가더라도 '3'이라는 숫자를 사용할 수 있다.
		 */
	}
	
	public static Supplier<String> getStringSupplier() {
		String hello = "Hello";
		Supplier<String> supplier = () -> {
			String world = "World";
			return hello + world;
		};
		
		return supplier;
	}
}

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함