[JAVA] 함수형 인터페이스
함수형 프로그래밍 (Functional Programming)
자료처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임의 하나
프로그래머들이 일하는 새로운 패러다임을 제시함
함수에 동작에 의한 변수의 부수적인 값 변경을 원천 배제함으로써 이런 종류의 오류를 방지
외부 변수를 사용하더라도, 그 본체에 접근해서 변경하는것이 아니라 인자를 넣어서 사본으로 복사해가서 작업을 하기 때문에 어떤 작업을 하든 부작용은 일어나지 않는다.
for문이나, while문의 경우 특정 변수의 상태 변화, 즉 부수효과를 필요로 한다.
특징존재
1. Input , Output이 있다.
2. 외부환경으로부터 독립적임
3. 외부환경으로부터 독립적이기 때문에 같은 Input에 대해서는 동일한 Output을 만들어낸다. (순수함수)
4. 부작용에 의한 문제로부터 자유로움 , 부작용이란? 변경된 다른 상태에 접근할때 다른 오류를 만들어낼 수 있는 가능성
함수형 프로그래밍은 "선언형"이다.
- 함수형 방식으로 짜인 함수, "순수함수"들은 인풋만 똑같으면 절대 다른 요인에 의한 변수가 없다.
- 함수를 값으로만 바라보고 프로그래밍함
함수도 "값"이다.
고계함수?
- 인자로 다른 함수를 받아 결과값을 내보내는 함수
- 값은 인자로 주어질뿐 아니라 결과값으로 반환되기도 함
- 다른 함수를 반환하는 함수도 고계함수에 속함
// javascript
conat calc = (num1, num2, op) => op(num1, num);
const add = (num1, num2) => num1 + num2;
const multiply = (num1, num2) => num1 * num2;
const power = (num1, num2) => Math.pow(num2, num1);
calc(2,3, add)
calc(2,3, multiply)
calc(2,3, power)
함수 컴비네이터
- 배열이나 리스트에서 많이 사용디는 컬랙션
(참고) 자바스크립트에서 구현하기?
- Lodash란 라이브러리의 기능을 이용해서 함수형 언어로 만들기
- 기존의 함수를 사용하려면 , for, while을 사용해서 상태를 많이 변경해야하지만 Loadsh 라이브러리 기능을 사용해서 함수형 언어로 만들 수 있음
var students = [
new Student("홍길동", "문과", "문학"),
new Student("전우치", "이과", "기계"),
new Student("임꺽정", "이과", "화학"),
]
console.log(
_(students)
.filter((i) => i.division === '이과')
.take(3)
.map((i) => `${i.name}($i.major})`)
.reduce((sum,i) => sum + " " + i)
)
함수형 인터페이스 (Functional Interface)
추상 메소드를 딱 하나만 가지고 있는 인터페이스이다. SAM (Single Abstract Method) 인터페이스이며 @FuncationInterface 애노테이션을 가지고 있는 인터페이스이다.
// 추상 메소드의 예
public interface RunSomething {
void doIt()
// abstract void doIt()
}
위 예는 추상메소드이다. abstract가 있는데 사실 생략된것. 하지만 아래는 함수가 추상메소드를 2개 가지고 있기 때문에 함수형 인터페이스라고 할 수 없다.
// 추상 메소드가 아니다.
public interface RunSomething {
void doIt();
void doItAgain();
}
아래와 같은 경우는 함수형 인터페이스인가? 인터페이스가 맞다.
다른 형태의 함수가 들어와도 추상 메소드가 몇개인가가 중요하다. 한개면 무조건 Functional Interface이다
Functioan Interface라는것을 구분하기 위해서 상단에 @FunctionalInterface Annotation을 붙여준다. Interface를 견고하게 관리할 수 있는 방법이다.
@FunctionalInterface
public interface RunSomething {
void doIt();
static void printName(){
System.out.println("Rosy");
}
default void printAge(){
System.out.println("??");
}
}
람다표현식
- JAVA 8버전 이전에는 다음과 같이 사용하였다. 하지만 람다가 나오면서 람다형태의 코드를 사용하면서 줄여서 사용할 수 있다. = 람다 표현식
함수형 인터페이스의 인스턴스를 만드는 방법으로 쓰일 수 있으며 코드를 줄일 수 있다. 메소드 매개변수, 리턴 타입, 변수로 만들어 사용할 수도 있다.
- 함수의 형태를 인라인으로 표현한 Object
// 이전
RunSomething runSomething = new RunSomething() {
@Override
public void doIt() {
System.out.println("Hello");
}
};
// 발전
RunSomething runSomething = () -> System.out.println("Hello");
자바에서 함수형 프로그래밍
함수를 First class object로 사용할 수 있다.
순수 함수 (Pure function)
- 사이드 이펙트 만들 수 없다. 함수밖에 있는 값을 변경하지 못한다.
- 상태가 없다
고차 함수 (Higher-Order Function
- 함수가 함수를 매개변수로 받을 수 있고 함수를 리턴할 수 있다.
불변성
자바에서 기본으로 제공하는 함수형 인터페이스
Function<T,R>
//기본
Function<Integer, Integer> plus10 = (number) -> {
return number + 10;
};
System.out.println(plus10.apply(1));
//함수 응용
Function<Integer, Integer> multiply2 = (number) -> number * 2 ;
System.out.println(multiply2.apply(1));
//두 함수 조합
System.out.println(plus10.compose(multiply2));
//function 뒤에다가 붙임
plus10.andThen(multiply2);
BIFunction<T,U,R>
- T,U를 받아서 R타입을 return하는 방식을 의미한다
Consumer
- 받아서 Return하지 않는다.
Consumer<Integer> printT = (i) -> System.out.println(i);
printT.accept(10);
Predicate
//True , False를 Return 해주는 함수 Interface
Predicate<String> startsWithYou = (s) -> s.startsWith("rosy");
Predicate<Integer> isEven = (i) -> i % 2 == 0;
Supplier
- 어떤값을 가져오는 Interface
Supplier<Integer> get10 = () -> 10;
System.out.println(get10);
Runnable
<출처>
1. 더 자바: Java 8