Programming/JAVA

[JAVA] 함수형 인터페이스

RosyPark 2022. 4. 29. 07:52

함수형 프로그래밍 (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

2. 함수형 프로그래밍이 뭔가요?