Right now do !

[JAVA] C#개발자를 위한 JAVA: Lambda Expression편

by 지금당장해

이번 글에서는 JAVA의 Lambda Expression을 별도로 다루려고 한다. JAVA 8에서 추가로 나온 개념이기도 하며 C#에서도 진지하게 공부 해본적이 없는 개념이라 비교 정리가 불가능 하다고 판단 했기 때문이다. (후딱 정리하고 최신 C#문법도 비교 해서 정리해야 겠다.)


# Lambda Expression (람다식)

왜 이렇게 부르는지 뭐 어떤 언어에서 이런 개념이 접합이 되었는지 주절 주절 써 있는데 그걸로는 난 이해 못하겠고 내가 이해 하자면 이렇다. Interface를 활용하는 방법중에 하나가 익명 객체를 정의하여 이를 바로 불러 쓰는 것이다. 근데 이역시도 뭔가 마땅치 못한 것이다. 책에서는 Thread를 예를 들어 많이 설명을 하고 있다. Thread를 생성해서 start를 할껀데 Runnable을 익명으로 생성하고 거기에 run추상을 재정의 해야 한다. 근데 이역시도 하기 싫은 것이다.


그래서 아래와 같이 한다. (이것이 람다식 이다.)

Thread thread = new Thread(()->{

// 실행 내용 

}); 

모두 생략 되어 있다. Runnable을 new하는 절차도 run함수를 재정의 하는 절차도....


람다식의 정의: 책에서 내린 인용하자면 익명「함수」를 생성하기 위한 식 이란다. 대충 읽고 넘어가려다 뭔가 이상하다. 익명 객체가 아니라 익명 함수를 정의 한다고 ..... 다시 돌이켜 보면 람다식을 쓰는 형식이 아래와 같다.


인터페이스_형 인터페이스_객체 = (인자)->{함수 구현체} 


좌항은 형과 객체인데 우항은 필시 함수의 형태를 띠고 있다. 어쩌라는 것인가? 다 좋은데 좌측에 정의된 어떤 함수에 우항의 함수 정의를 대입시키라는 것인가? 애시당초 좌 항에 인터페이스에는 추상 함수가 하나만 가능 하다. 즉 람다식을 받아들이려면 인터페이스 정의에 제약이 있다는 것이다. 다시 한번 개념을 정리 하자면 대단히 많이 생략되어 있지만 ... 좌항의 인터페이스 객체의 유일한 추상 메서드에 우측에 정의 하고 있는 『익명 함수 정의를 주입하는 개념』 이라고 람다식을 정의 할 수 있다.


# @FunctionalInterface

 이 Annotation을 지정 하여 하나의 추상 메소드를 갖는 인터페이스를 제약하여 정의 한다. 심지어 이 Annotation없어도 된단다. 추상 메서드 하나만 있으면 된다. 이 어노테이션은 혹여 누군가 해당 인터페이스에 눈치 없이 추상 메서드를 또 넣을까봐 명시적으로 지정하는것 뿐이다.

예를 하나 들자면 Thread에 인자로 사용되는 위에서도 언급한 Runnable도 이 Annotation이 지정되어 있다. (추상메서드를 하나만 정의 하라는 것이지 정적 Default 메소드는 추가 할 수 있다.) 


람다식의 Member참조

① 람다식 블럭 내에 this는 해당 Lambda식 구현 Class의 this객체를 의미 한다. 언듯 당연하지 라고 생각 하겠지만 여기서 이 부분을 집고 넘어가는 것은 익명 객체선언과 차이(혼란)을 명시 하고자 함이다. 익명 객체의 this는 익명객체 Self 이기 때문이다. 그도 그럴 것이 람다식은 엄연히 함수를 구현 하는 것이니 자신(Self)라고 할 만한 것이 없으나 익명 객체는 엄연히 Class를 선언하는 것이므로 선언 자체가 자신이라고 할 수 있다.


② 람다식의 구현 위치가 Nested Class인 경우 this는 무엇을 지칭하게 되는가? 구현이 이루어진 Nested를 의미 한다. Outer Class를 지칭 하려면 다음과 같이 한다.

OuterClass.this.Member;

# 람다식의 Method Local변수 참조

람다식의 구현이 Class member를 정의하는 경우도 있지만 말 그대로 식이기 때문에 method내에서 어떤 객체의 실행을 정의하는 목적으로 사용되기도 한다. 이러다 보니 method정의내의 람다식은 해당 method의 Local변수에 접근 할 수 있느냐에 대한 논란이 생긴다. 결론부터 이야기 하면 일단 접근은 할 수 있다. 그런데 이렇게 접근한 변수는 final이 된다고 한다. (왜 그렇지.... 아직은 이해가 가지 않는다. 나중에 이해가 가면 이 부분에 이해 간 부분을 기술 하겠다.)



public class Main {

    public static void main(String[] args) {
	// write your code here
    }

    public void methodOfContainsLambda(String sParam) {
       int numaricVal = 100;
       numaricVal = 100*100;
       sParam = sParam + "님 안녕하세요?";
       MyFunctionalInterface fi = () -> {

       System.out.println(sParam);
       if ( numaricVal > 100)
       {
           System.out.println(numaricVal);
       }

     };

     fi.method();

  }

}

위와 같이 람다식 내부에서 함수의 로컬변수를 사용했는데 이것이 함수내에서 수정이 이루어지면 아래와 같은 컴파일 오류가 발생한다.
Error:(20, 32) java: local variables referenced from a lambda expression must be final or effectively final


블로그의 정보

지금 당장 해!!!

지금당장해

활동하기