Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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 31
Archives
Today
Total
관리 메뉴

풀이 보관함

[Javs SE 8] Function<T, R> 과 apply() 본문

etc.

[Javs SE 8] Function<T, R> 과 apply()

viin 2024. 4. 15. 17:34

 

Function<T, R> 과 apply()

T : input type R : return type

 

 

background


기본적으로 자바는 타입이 ‘기본형’과 ‘객체형’이 있다. 그냥 기본형이 아닌건 다 객체다.

 

📌 기본형 (Primitive Type)

- 논리 : boolean
- 문자 : char
- 정수 : byte, short, int, long
- 실수 : float, double

 

 

함수가 객체라면 다른 객체들처럼 컨테이너에 저장할 수 있어야 하는게 아닐까?

그런데 클래스 안에서 선언하는거 이외에 함수를 객체로써 사용을 하시나요? 

 

C++에서는 함수 객체 개념을 위해 std::function, std::find가 있는데 Java는 어떨까?!

 

 

Function (java.util.function)


Function (Java Platform SE 8 )

 

Function (Java Platform SE 8 )

 

docs.oracle.com

This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

 

Java 8 에서 부터 제공하는 Function 를 이용하면 함수를 어떤 변수에 할당할 수 있다.

 

 

이 포스팅에서는 이런 개념이 있다는 것을 알리는 것이 목적이므로,  Interger 매개변수 1개에 Integer 반환 타입1개를 을 다루겠습니다. 

 

💡 function에서 매개변수의 개수와 타입에 따라 여러 종류를 지원하고 있습니다.

  • 기본형 매개변수는 따로 XXFunction이 인터페이스가 있음
    • IntFunction
  • 기본형 매개변수에 기본형 리턴값도 따로 XXtoYYFunction이 인터페이스가 있음
    • DoubleToIntFunction

 

사용  방법


 

# 선언 방법

Function<매개변수타입, 리턴타입> 변수명
Function<Integer, Integer> fn = (Integer x) -> Operation.op2(x);

이런 식으로 함수나 람다를 저장할 수 있다. 

 

 

# 호출 방법

funtion에 내장된 apply() 라는 메서드를 이용해 호출한다. 

for(Function<Integer, Integer> op : tasks)
{
       int e = 1;
       x = op.apply(e); // apply에 파라미터를 건낸다. 
       System.out.println(e);
}

 

 

 

활용 예시


 

예시 1

람다나 함수를 배열로 저장할 수 있다. 할당할 수 있으니까!

static Function<Integer, Integer>[] tasks = new Function[]{
        n -> (Integer)n + 1,
        n -> (Integer)n - 1,
        n -> (Integer)n * 2
};

 

 

예시 2

덕타이핑을 통한 유연한 프로그래밍이 가능해진다. 

 

한 클래스에 여러 연산이 있는 예시를 작성해보았다. 

static class Operation
{
    static int op1(final int x)
    {
        return x + 1;
    }

    static int op2(final int x)
    {
        return x-1;
    }

    static int op3(final int x)
    {
        return x*2;
    }
}

 

 

 

만약 위 멤버 함수를 모두 한번씩 호출해야한다고 생각해보자.

한 줄씩 호출해도 되지만  Function을 매개변수로 이용해서 사용 방법을 통일화 할 수 있다. 

static int calc(Function<Integer, Integer> op, final int n){
        return op.apply(n);
}

 

 

 

>> main

System.out.println("멤버 함수 op1 호출 : " + calc(Operation::op1, 5));
System.out.println("멤버 함수 op2 호출 : " + calc(Operation::op2, 5));
System.out.println("멤버 함수 op3 호출 : " + calc(Operation::op3, 5));

 

만약 호출자체가 사용자의 입력에 달린 것이라면? 런타임에 어떤 함수가 호출될지 고를 수 있는 동적 프로그래밍이 되는 것이 큰 특징이다. 

 

 

>> 결과값

멤버 함수 op1 호출 : 6
멤버 함수 op2 호출 : 4
멤버 함수 op3 호출 : 10

 

 

 

어떻게 활용될 수 있나 스스로 궁리하느라 예시가 빈약한 점 죄송하다는 말을 하며.. 

 

 

 

일단 이쯤하면 어떻게 사용하는지는 알았을 것이다. 

진짜 장점은 간단한 람다와 반복문에서 극대화되는 것 같다!! 

간단한 연산을 여러번 반복해야한다면 Funtion을 컨테이너에 저장한 뒤 활용하면 좀 더 코드를 깔끔하게 만들 수 있다. 

static Function<Integer, Integer>[] tasks = new Function[]{
            x -> Operation.op1((Integer) x),
            x -> Operation.op2((Integer) x),
            x -> Operation.op3((Integer) x)
    };

 

 

이러면 똑같은 apply라는 함수로 여러 연산을 계산할 수 있다.

for(Function<Integer, Integer> op : tasks) {
            System.out.println("반복문 테스트 : " + op.apply(5));
}

 

반복문 테스트 : 6
반복문 테스트 : 4
반복문 테스트 : 10

 

 

 

 

마치며..


Function 클래스에는 아래 그림처럼 함수 실행 전에 뭘 해야한다고 조건을 주는 compose, 실행 후 조건을 주는 andThen() 이라는 것도 있다. 하지만 아직 쓸 일이 없었으므로 다음에 포스팅해보겠습니다!

 

첨언하자면 숨바꼭질2라는 문제를 풀다가 연산 if문으로 분기 하기 싫어서 여기까지 와버렸습니다..

 

이렇게 if문 범벅인 코드를 

for(int i=0; i<3; ++i)
{
    if(i==0) x = e + 1;
    else if(i ==1) x = e - 1;
    else if(i==2) x = e *2;

    if(x == k) ++cnt;
    if(x < 0 || x >= MAX_SIZE  || visited[x]) continue;
    q.offer(x);
}

 

짜잔 간단하게 바꿀 수 있습니다.

for(Function<Integer, Integer> op : tasks)
{
    x = op.apply(e);
    
    if(x == k) ++cnt;
    if(x < 0 || x >= MAX_SIZE  || visited[x]) continue;// || ((visited & (1<<x))!=0)) continue;
    q.offer(x);
}

 

 

만약에 연산의 수가 계속 변동된다면 for문의 반복 횟수도 고쳐야 하며, 내부 if문을 추가해야 하지만

Function을 쓰면 배열에 추가할 함수만 더 추가해주면 그만이니 정말 편리한 기능입니다. 

 

 

 

 

Function보다 if문이 속도는 더 빠르다는 사실을 알리며 총총…