ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 함수형 인터페이스와 람다 표현식 소개
    프로그래밍/Java 2022. 6. 7. 22:24

    함수형 인터페이스


    • 추상 메서드를 하나만 가지고 있는 인터페이스
    • Single Abstract Method 인터페이스
    • @FunctionalInterface 애노테이션을 가지고 있는 인터페이스 
    • 다른 형태 (예를들어, static 혹은 default)의 메서드가 있더라도 함수형 인터페이스 이며, 추상 메서드가 하나여야 한다.
    • @FunctionalInterface 는 Java 가 제공해주는 애노테이션이며, 함수형 인터페이스 조건위반시 에러를 띄운다.
    @FunctionalInterface
    public interface RunSomething {
      int doIt(int number);
      //void doIt();
    
      static void printName() {
        System.out.println("lhk");
      }
    
      default void printAge() {
        System.out.println("100");
      }
    }

    이 처럼 직접 함수형 인터페이스를 만들 수도 있지만, 자바에서 제공되는 함수형 인터페이스들을 사용하면 쉽게 정의가 가능하다.

    https://hyokeun0419.tistory.com/98?category=1006478

     

     

    익명 내부 클래스


    • 클래스 선언과 객체의 생성을 동시에 하며 단 한번만 사용될 수 있고 오직 하나의 객체만 생성할 수 있는 일회용 클래스이다. 
    • 이름이 없기 때문에 생성자도 가질 수 없다.
    • 부모 클래스의 이름이나 구현하고자 하는 인터페이스의 이름을 사용해서 정의하기 때문에 단 하나의 클래스를 상속 받거나 하나의 인터페이스만을 구 현할 수 있다.
    public class Foo {
      public static void main(String[] args) {
        
          RunSomething runSomething = new RunSomething() {
            @Override
            public void doIt() {
             System.out.println("hello");
            }
          };
      }
    }

     

     

     

    람다 표현식


    • 익명 함수라고도 불리며, 객체를 생성하지 않아도 메서드를 사용할 수 있다.
    • 함수형 인터페이스의 인스턴스를 만드는 방법으로 쓰일 수 있다.
    • 코드를 줄일 수 있다.
    • 메소드 매개변수, 리턴타입, 변수로 만들어 사용할 수 있다.
    • (인자 리스트) -> {바디}
    public class Foo {
      public static void main(String[] args) {
        RunSomething runSomething = (number) -> {
          return number + 10;
        };
      }
    }

    인자 리스트

    • 인자가없을때:()
    • 인자가 한개일 때: (one) 또는 one
    • 인자가 여러개 일 때: (one, two)
    • 인자의 타입은 생략 가능, 컴파일러가 추론(infer)하지만 명시할 수도 있다.
      (Integer one,
      Integer two)

    body

    • 화상표 오른쪽에 함수 본문을 정의한다.
    • 여러줄인경우에{ }를사용해서묶는다.
    • 한 줄인 경우에 생략 가능, return도 생략 가능

    변수 캡처 (Variable Capture)

    • 로컬변수캡처
      • final이거나 effective final 인 경우에만 참조할 수 있다.
      • 그렇지 않을 경우 concurrency 문제가 생길 수 있어서 컴파일가 방지한다. 
    • effective final 
      • 이것도 역시 자바 8부터 지원하는 기능으로 “사실상" final인 변수.
      • final 키워드 사용하지 않은 변수를 익명 클래스 구현체 또는 람다에서 참조할 수 있다. 
    • 익명 클래스 구현체와 달리 ‘쉐도윙’하지 않는다.
      • 익명 클래스는 새로 스콥을 만들지만, 람다는 람다를 감싸고 있는 스콥과 같다.

     

    아래 코드를 통해 로컬 클래스, 익명 클래스, 람다에서의 변수 캡처(Variable Capture) 개념을 살펴보자.

    package me.whiteship.java8to11._01_functional_interface;
    
    import java.util.function.Consumer;
    import java.util.function.IntConsumer;
    
    public class Foo {
    
      public static void main(String[] args) {
        Foo foo = new Foo();
        foo.run();
      }
    
      private void run() {
    
        int baseNumber = 10; // 사실상 final , final 이라는 키워드 없이도 아래 세 경우에 final 로 적용된다.
    
        // 1. 로컬 클래스 (쉐도잉)
        class LocalClass {
          void printBaseNumber() {
            // 위에 변수가 선언되어 있지만, 이를 무시하고 내부에 정의되어 있는것을 참조 => 쉐도잉 
            int baseNumber = 11;
            System.out.println(baseNumber); // 11
          }
        }
        // 2. 익명 클래스 (쉐도잉) 
        Consumer<Integer> integerConsumer = new Consumer<>() {
          @Override
          public void accept(Integer baseNumber) {
            // 위에 변수가 선언되어 있지만, 이를 무시하고 내부에 정의되어 있는것을 참조 => 쉐도잉 
            System.out.println(baseNumber); 
          }
        };
    
        // 3. 람다 , 쉐도잉 X (가려지지 않으며 run 메소드와 scope 이 같다.)
        IntConsumer printInt = (i) -> {
          // 외부에 선언된 baseNumber 를 참조하며, 값을 변경할 수 없다. 
          // effective final 개념이 적용된 것이며, 외부에서 값을 변경하면 적용된 final 이 풀리고 람다에서는 사용하지 못하게된다.
          System.out.println(i + baseNumber);//
        };
        
        printInt.accept(10);
        integerConsumer.accept(100);
      }
    }

     

     

     

    자바에서 함수형 프로그래밍 


    • 함수를 First class object 로 사용할 수 있다.
    • 순수 함수 (Pure function)
      •  사용할 때 함수 내부, 함수가 전달받은 파라미터만 사용해야한다.
      •  사이드 이팩트가 없다. (함수 밖에 있는 값을 변경하지 않는다.)
      • 상태가 없다. (함수 밖에 있는 값을 사용하지 않는다.)
    • 고차 함수
      • 함수가 함수를 매개변수로 받을 수 있고 함수를 리턴할 수 있다.
    package me.whiteship.java8to11._01_functional_interface;
    
    public class Foo {
    
      public static void main(String[] args) {
        RunSomething runSomething = (number) -> {
          return number + 10;
        };
        
        System.out.println(runSomething.doIt(1)); // 11 (순수함수)
        System.out.println(runSomething.doIt(1)); // 11
        System.out.println(runSomething.doIt(1)); // 11
        System.out.println(runSomething.doIt(2)); // 12
        System.out.println(runSomething.doIt(2)); // 12
        System.out.println(runSomething.doIt(2)); // 12
      }
    }

     

     

     

    참고


    백기선 - 더 자바, Java8
    https://www.inflearn.com/course/the-java-java8/dashboard

    '프로그래밍 > Java' 카테고리의 다른 글

    메소드 레퍼런스  (0) 2022.06.08
    자바에서 제공하는 함수형 인터페이스  (0) 2022.06.07
    Metaspace  (0) 2022.05.06
    배열 Parallel 정렬  (0) 2022.05.06
    CompletableFuture (5)  (0) 2022.05.06
Designed by Tistory.