Java

함수형 인터페이스와 람다 표현식 [더 자바, Java 8]

깊게 생각하고 최선을 다하자 2022. 10. 4. 02:20

1) 함수형 인터페이스

- 인터페이스에 추상 메서드가 하나만 있으면, 함수형 인터페이스입니다.

  자바 8부터는 static 메서드와 default 메서드를 정의할 수 있습니다. 

  이 때, 추상 메서드가 여전히 1개라면 함수형 인터페이스입니다. 

package me.whiteship.java8to11;

public interface RunSomething{

   void doIt();
   
   static void printName(){
      System.out.println("Keesun");
   }
   
   default void printAge(){
      System.out.println("40");
   }
}

- 함수형 인터페이스를 선언할 때, @FunctionalInterface를 붙여줄 수 있고,

   이 때, 함수형 인터페이스의 조건을 위반하면 컴파일 단계에 에러가 납니다.

  @FunctionalInterface를 추가해서 인터페이스를 견고하게 관리하면 좋습니다. 

package me.whiteship.java8to11;

// 에러 발생!
@FunctionalInterface
public interface RunSomething{

   void doIt();
   
   void doAgain();
}

 

- 인터페이스를 만들면, 자바 8 이전에는 익명 내부 클래스를 만들어서 썼습니다.

package me.whiteship.java8to11;

public class Foo {

    public static void main(String[] args){
    
        RunSomething runSomething = new RunSomething(){
          @Override
          public void doIt(){
              System.out.println("Hello");
          }
        };
    }
}

- 자바 8부터는 인터페이스가 하나인 경우에는 줄여서 쓸 수 있는 문법이 생겼습니다.

  람다 표현식은 함수형 인터페이스를 구현할 때 쓸 수 있는, 람다 형태의 표현식입니다. 

package me.whiteship.java8to11;

public class Foo {

    public static void main(String[] args){
    	RunSomething runSomething = () -> System.out.println("Hello");
    }
}

- 만약에 한 줄이 아닌 경우에는 다음과 같이 줄여줍니다. 

package me.whiteship.java8to11;

public class Foo {

    public static void main(String[] args){
    	RunSomething runSomething = () -> {
           System.out.println("Hello");
           System.out.println("Lambda"); 
        };
    }
}

- 함수를 다음과 같이 실행할 수도 있습니다.

  람다 표현식은 자바에서 특수한 형태의 오브젝트라고 볼 수 있습니다. 

  함수형 인터페이스를 인라인으로 구현한 오브젝트라고 볼 수 있습니다.

package me.whiteship.java8to11;

public class Foo {

    public static void main(String[] args){
    	RunSomething runSomething = () -> System.out.println("Hello");
        runSomething.doIt();
    }
}

- 사실상 자바라는 언어는 객체지향 언어이기 때문에, 이것을 변수에 할당하고,

  메소드 파라미터로 전달하고, 또는 리턴 타입으로 리턴을 할 수 있습니다. 

  즉, 람다 표현식을 메소드 파라미터로 전달하거나, 리턴하는 것도 가능합니다. 

  이것은 자바에서 함수를 first-class object로 사용할 수 있다는 것에 해당합니다. 

  고차 함수라는 표현도 있는데, 함수가 함수를 파라미터로 갖는다거나,

  함수가 함수를 리턴하는 것도 가능한 것을 의미합니다.

  자바에서는 함수는 특수한 형태의 오브젝트일 뿐입니다. 

  따라서 오브젝트를 리턴타입으로 쓰거나, 파라미터로 쓰는 것이 당연한 것입니다. 

 

- 순수 함수는 수학적인 함수입니다. 

  수학적인 함수라고 생각할 때, 가장 중요한 것은 입력 받은 값이 동일한 경우

  결과가 같아야 한다는 것입니다. 

  이런 결과가 보장 받지 못한다면, 함수형 프로그래밍이라고 보기 어렵습니다. 

  예를 들어, 다음과 같은 경우는 순수 함수라고 보기 어렵습니다.

  baseNumber라는 상태값에 의존하기 때문입니다. 

package me.whiteship.java8to11;

public class Foo{

    public static void main(String[] args){
      
         RunSomething runSomething = new RunSomething(){
              int baseNumber = 10;
              
              @Override
              public int doIt(int number){
                  return number + baseNumber;
              }
         };
     }
}

 

- 또 다른 케이스로는 외부에 있는 값을 변경하려는 경우가 있습니다.

  이러한 경우도 순수 함수라고 볼 수 없습니다.

package me.whiteship.java8to11;

public class Foo{

    public static void main(String[] args){
      
         RunSomething runSomething = new RunSomething(){
              int baseNumber = 10;
              
              @Override
              public int doIt(int number){
                  baseNumber++;
                  return number + baseNumber;
              }
         };
     }
}

 

- 자바에서 함수형 프로그래밍의 초석으로 제공하는 함수형 인터페이스와 람다 표현식은

  굳이 함수형 프로그래밍을 안하더라도 사용할 수 있습니다. 

  하지만 만약 함수형 프로그래밍을 순수하게 하겠다 하면, 

  순수 함수나 immutability를 고려해야 합니다. 

 

 

참고

- 백기선, 더 자바, Java 8