[CHAPTER 17] 함수형 프로그래밍 기타 내용 [실습 리뷰]
세 번째 복습 리뷰는 FP 마지막 스터디 에서 진행했던 새로운 코딩 패턴에 대해 다뤄보려고 합니다.
관련 내용은 아래 포스팅을 참고하세요 :-)
한 번 진행했던 실습 내용에 대해, 기능별로 나눠 포스팅을 진행해보겠습니다.
디폴트 메소드와 Optional 의 경우 관련 포스팅에 내용이 더욱 자세히 나와있습니다.
그렇기 때문에 따로 진행하지는 않겠습니다.
1. 조건부 실행
FP 첫 시간에 배웠던 것 중 한 가지는 함수를 파라미터로 넘길 수 있다는 것이었습니다.
조건부 실행은 이 메커니즘을 응용한 방법으로 특정 조건이 되었을 때, 어떤 행위를 수행할지 파라미터를 넘기는 것을 의미합니다.
이런 행위를 왜 하는가에 대해 생각해볼 때 다음과 같은 요구사항을 생각해볼 수 있습니다.
1 2 3 4 5 6 7 8 9 10 | /** * 특정 행위를 수행하는 함수1. * * <pre> * 실패했을 때 errorValue 를 이용해서 뭔가를 수행하는 듯. * </pre> * * @param errorValue */ public void func1(String errorValue); | cs |
그래서, 이 메소드를 이용하는 곳을 살펴보니 아래와 같았습니다.
1 2 3 4 5 6 7 | // 에러 값을 미리 생산. // errorValueCreator 의 실행시간은 3초. // 실행시간을 줄일 수는 없어보임. String errorValue = errorValueCreator(); // 결국, 실패하나 성공하나 무조건 errorValueCreator 가 실행되는 상황.. func1(errorValue); | cs |
func1 을 실행하기 위해서는 errorValue 를 구해야하는 상황이며, 이는 func1 의 결과가 성공하나 실패하나 무조건 errorValueCreator 를 실행해야함을 의미합니다.
물론 이 방법을 우회할 수 있는 방법은 많으나, 조건부 실행에서는 다음과 같은 방법을 제시합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /** * 특정 행위를 수행하는 함수1. * * <pre> * 실패했을 때 errorValue 을 생산하는 함수를 인자로 받음. * </pre> * * @param errorValue */ public void func1(Supplier<String> errorValueSupplier); // 동적 파라미터화 이용. // errorValueCreator 는 내부적으로 실패했을 때만 실행함을 보장. func1(() -> errorValueCreator()); | cs |
즉 실패 시 어떤 행위를 할지를 동적 파라미터화 형태로 받음으로, 실패할 때만 errorValueCreator 가 실행되도록 조정할 수 있어 보입니다.
또한, 동적 파라미터화는 다형성을 내포하고 있기 때문에 다양한 errorValueCreator 를 제작하여 파라미터로 넘길 수 있을 것 처럼 보이네요.
이러한 조건부 실행을 사용하는 예제는 Optional::orElseGet 입니다.
Optional 이 비어있을 때, orElse 에 디폴트 값을 미리 넣는 반면, orElseGet 는 데이터가 비어있을 때 디폴트 값을 생성하는 함수를 실행하도록 합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // orElse 사용. String name1 = Optional.ofNullable(testVO). flatMap(TestVO::toTestVO2Optional). flatMap(TestVO.TestVO2::toTestVO3Optional). flatMap(TestVO.TestVO3::toTestVO4Optional). flatMap(TestVO.TestVO4::toNameOptional). orElse(GetDefaultResult()); // orElseGet 사용. String name2 = Optional.ofNullable(testVO). flatMap(TestVO::toTestVO2Optional). flatMap(TestVO.TestVO2::toTestVO3Optional). flatMap(TestVO.TestVO3::toTestVO4Optional). flatMap(TestVO.TestVO4::toNameOptional). orElseGet(() ->GetDefaultResult()); | cs |
두 메소드는 미묘하지만, 실행이 다릅니다.
2. 커링 함수
커링 함수는 함수를 완성시키지 않고, 파라미터를 받아 또 다른 함수를 만드는 기법입니다.
조금 더 쉽게 표현하면, 메소드의 결과가 함수임을 말합니다.
이를테면, 이런거?
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 | /** * 이름에 타이틀을 붙이는 함수 제작 * * @param title * @return */ public static UnaryOperator<String> GetTitleFunction( String title) { return (value) -> String.format("%s %s", title, value); } // 멋있는 이라는 타이틀을 붙여주는 function.. UnaryOperator<String> awesome_func = GetTitleFunction("Awesome Guy"); // 아름다운 이라는 타이틀을 붙여주는 function.. UnaryOperator<String> beautiful_func = GetTitleFunction("Beautiful Lady"); System.out.println( beautiful_func.apply("강현지")); System.out.println( awesome_func.apply("남두현")); System.out.println( awesome_func.apply("유덕형")); System.out.println( awesome_func.apply("유형주")); // CONSOLE LOG // Beautiful Lady 강현지 // Awesome Guy 남두현 // Awesome Guy 유덕형 // Awesome Guy 유형주 | cs |
동작을 값으로 가진다는 메커니즘은 이런 아이디어를 또 만들어내는군요. @.@
이를 보고, 쓸모 없어보인다고 생각하면 오산!
커링함수들의 출력이 함수형 인터페이스란 것을 생각한다면,
Stream API 의 파이프라인에 들어갈 함수들에 대한 모듈화를 해줄 수 있음을 의미합니다.
1 2 3 | Arrays.asList("강현지", "남두현", "유덕형", "유형주"). stream(). map(GetTitleFunction("More Developer style person")); | cs |
이렇게 말이죠!!!!!!
이 것으로 FP 스터디에 다루고자 했던 모든 내용은 끝났으며, 처음 4월에 생각했던 OOP & FP 의 목표는 마무리되었습니다.
여기까지 달려온 여러분 모두 수고하셨습니다.
이 곳까지 왔을 때,
4월의 그 때보다 성장 했기를 바라며,
Effective 시리즈로 지금 이 시점보다 진보하길
기도합니다.
Good-Bye [OOP & FP].
'스터디 > [STUDY] FP' 카테고리의 다른 글
[CAHPTER 15] Stream API 리뷰 (2) [과제 리뷰] (2) | 2017.08.13 |
---|---|
[CHAPTER 14] Stream API 리뷰 (1) [과제 리뷰] (2) | 2017.08.13 |
[CHAPTER 17] Optional + 디폴트 메소드 + 기타. (0) | 2017.08.03 |
[CAHPTER 15] Stream API 리뷰 (2) (3) | 2017.07.26 |
[CAHPTER 14] Stream API 리뷰 (1) (0) | 2017.07.20 |