https://www.inflearn.com/course/the-java-java8/dashboard
강의를 공부하며 생각을 정리한 글입니다.
자바의 함수형 프로그래밍
자바스크립트로 함수형 프로그래밍에 입문해서 그런지 자바로 함수형 프로그래밍을 하는 것이 뭔가 낯설고 신기했다. 자바스크립트는 타입이 없기 때문에 그저 순수함수와 고차함수를 만들어내는 데에만 집중했었다. 하지만 자바에는 타입이 존재한다. 따라서 함수형 프로그래밍을 하려면 어떤 함수든지 그 함수를 참조할 변수의 타입을 정해줘야한다. 그걸 위해서 함수형 인터페이스라는 것이 존재한다. 처음 자바를 배울 때 함수형 인터페이스는 추상 메소드를 딱 하나만 들고 있는 인터페이스라고 배웠다. 그래서 이걸 어디에 쓴다는거야? 하면서 흘려들었는데 최근 함수형 프로그래밍에 관심이 생기고 나서 다시보니 함수형 인터페이스는 자바로 함수형 프로그래밍을 하기 위한 발판이었다. 이 사실을 알게 되니 사용법을 몰라서 오랫동안 방치해두던 물건의 쓰임새를 알게된 것 마냥 신기하고 재밌었다 ㅋㅋㅋ
@FunctionalInterface
public interface Functional {
void execute();
static void f1() {
// logic
}
default void f2() {
// logic
}
}
함수형 인터페이스에는 @FunctionalInterface 어노테이션을 붙여주는 것이 좋다. 해당 인터페이스가 함수형 인터페이스임을 명시적으로 알려줌과 동시에 만약 추상 메서드가 2개 이상이면 에러도 던져준다.
static 과 default 메서드는 여러개 있어도 추상 메서드가 결국 하나이므로 위의 코드는 에러가 나지 않는다.
Functional run = new Functional() {
@Override
public void execute() {
System.out.println("hi !");
}
};
//람다 ver
Functional run2 = () -> System.out.println("hi !");
익명 클래스로 인터페이스의 구현체를 만들어줄 수도 있지만 람다 함수를 활용하면 아래처럼 더 편하게 만들 수 있다. 이렇게 생성한 함수는 일급 객체로써 다루는 것이 가능해진다.
기본제공 함수형 인터페이스
자바에서 제공해주는 기본 함수형 인터페이스에 대해서 알아보자. 함수형 프로그래밍을 위해 매번 함수형 인터페이스를 만들 필요는 없다. 자바에서 제공해주는 다양한 함수형 인터페이스들을 활용하면 되기 때문이다.
https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
설명도 잘 나와있어서 활용하기 수월할 듯 하다.
Function은 T 타입을 받아서 R 타입을 리턴해주는 함수이다.
Function<Integer, Integer> plus5 = i -> i + 5;
Function<Integer, Integer> multiply2 = i -> i * 2;
위의 두 함수는 순수함수이므로 다음과 같이 안전하게 조합이 가능하다.
System.out.println(plus5.apply(multiply2.apply(2))); //9
System.out.println(plus5.andThen(multiply2).apply(2)); //14
자바스크립트였다면 냅다 괄호쳐서 인자를 넘겼겠지만 자바에서는 apply를 통해서 구현한 함수를 호출해야한다. 결과값을 바로 다음 함수의 인자로 넣어줘도 되고 andThen 메소드를 통해 왼쪽에서 오른쪽으로 순차적으로 호출되도록 하는 것도 가능하다.
andThen은 default 함수로 구현되어져있다. 현재 함수를 먼저 실행한 후 인자로 받은 함수에게 넘겨주는 것을 볼 수 있다. andThen도 순수함수를 인자로 받는 고차함수인 것이다.
장단점은 있겠지만 아무래도 타입이 없는 js가 함수형 프로그래밍을 하기에 좀 더 편리하지 않나 하는 생각이 든다. 그도 그럴 것이 자바로 구현한 curry함수 코드를 봤는데 정말... ㅋㅋㅋㅋㅋㅋ
보기만해도 멍해진다..
람다의 특징
람다 함수는 선언된 위치의 스코프와 동일한 스코프를 가진다.
private void run() {
int base = 10;
IntConsumer printInt2 = base -> System.out.println(base);
}
위의 코드는 에러가 나게된다. run 함수와 동일한 스코프를 가지는데 이미 base 함수가 선언된 상황에서 또 base를 선언해서 인자로 받기때문이다. 이처럼 람다함수는 동일한 변수명으로 선언하면 기존의 변수가 덮어씌워지는 쉐도잉이 되지 않는다.
람다 참고하면 좋은 글
https://vagabond95.me/posts/lambda-with-final/
'함수형 프로그래밍' 카테고리의 다른 글
JS 함수형 프로그래밍 - 병렬처리 (0) | 2021.08.01 |
---|---|
JS 함수형 프로그래밍 - 비동기, Promise [2] (0) | 2021.08.01 |
JS 함수형 프로그래밍 - 비동기, Promise [1] (0) | 2021.08.01 |
JS 함수형 프로그래밍 - 지연성 (0) | 2021.08.01 |
JS 함수형 프로그래밍 - 이터러블, 이터레이터, 제너레이터 (0) | 2021.08.01 |