Language/Java

람다식(Lamdba Expressions) 정리

park_juyoung 2019. 3. 25. 19:23

람다식이란?

람다식은 수학자 알론조(Alonzo Church)가 발표한 람다 계산법에서 사용된 식으로, 이를 제자 존 매카시(John Macarthy)가 프로그래밍 언어에 도입했다.

Java8 버전부터 이 람다식(Lamdaba Expressions)을 지원하게 되었다.

람다식은 익명함수(anonymous function)을 생성하기 위한 식으로 객체 지향 언어보다 함수 지향 언어에 가깝다.

람다 형태는 매개변수를 가진 코드 블록이지만, 런타임 시에는 익명 구현 객체(추상메소드를 한개 포함한)를 생성한다.

 

위 설명처럼 람다식이란 일종의 함수형 프로그래밍에 적합한 문법적 표현방식이다.

함수형 프로그래밍은 병렬처리와 이벤트 지향 프로그래밍에 적합하며 딥러닝이나 빅데이터와 더불어 일종의 문법적 트렌드처럼 관심을 받고 있다.

 

Java에서도 이런 트렌드를 따라갈 필요를 느낀것 같으며, 람다식은 그 문법적으로 간결성으로 기존의 자바 문법보다 쉽게 함수를 표현할 수 있다.

그러나 람다 문법은 기존 java 문법과 확현히 다른 형태를 띠고 있기때문에 기존 java 개발자는 많은 생소함을 느낄 수도 있다.

람다식은 결국 로컬 익명 구현객체를 생성하게 되지만, 이 람다식의 사용 목적은 인터페이스가 가지고 있는 메소드를 간편하게 즉흥적으로 구현해서 사용하는 것이 목적이다.

만약 한개의 추상메소드를 갖는 인터페이스가 있을때, 이 추상메소드를 구현해서 사용하기 위해서는 다음과 같은 방법이 있을 것이다.

  1. 인터페이스를 직접 클래스로 구현해서 메소드를 호출

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    avajavajava//TestInterface.java
    @FunctionalInterface
    public interface TestInterface{
        public int plusAandB(int a, int b);
    }
     
    // TestInterfaceImpl.java
    public class TestInterfaceImpl implements TestInterface{
        
        @Override
        public int plusAandB(int a, int b){
            return a + b;
        }
    }
     
    // Main.java
    public class Main{
        public static void main(String[] args){
            TestInterface t1 = new TestInterfaceImpl();
            System.out.println(t1.plusAandB(34));
        }
    }
    cs

    위에 같은 방법으로 구현 시 인터페이스를 구현한 클래스를 재사용할 수 있는 장점이 있지만 재사용이 필요하지 않는 메소드를 만들어 사용해야 할때도 있을 것이다.

    그런 것들을 클래스로 구현하게 된다면 불필요한 class 파일이 늘어나게 될 것이다.

     

  2. 인터페이스를 익명구현객체로 구현해서 메소드를 호출

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // Main.java
    public class Main{
        public static void main(String[] args){
    //      TestInterface t1 = new TestInterfaceImpl();
    //      System.out.println(t1.plusAandB(3, 4));
            
            TestInterface t2 = new TestInterface(){
                
                @Override
                public int plusAandB(int a, int b){
                    return a + b;
                }
            }
        }
    }
    cs

    위 처럼 익명 구현객체를 사용하게 된다면 불필요한 클래스파일이 생기는 것도 막을 수 있고 프로그래밍 과정도 1번보다는 간결해진다.

     

  3. 람다식을 이용해서 더 간결하게 인터페이스 구현

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // Main.java
    public class Main{
        public static void main(String[] args){
    //      TestInterface t1 = new TestInterfaceImpl();
    //      System.out.println(t1.plusAandB(3, 4));
            
    //      TestInterface t2 = new TestInterface(){
    //           
    //          @Override
    //          public int plusAandB(int a, int b){
    //              return a + b;
    //          }
    //      }
            TestInterface t3 = (a, b) ->{return a + b; };
            System.out.println(t3.plusAandB(34));
        }
    }
    cs

함수적 인터페이스와 람다식 기본 문법

람다식을 사용하기 위해서는 구현할 인터페이스 가 필요하다.

람다식으로 구현하기 위한 인터페이스에는 조건이 하나있는데 한개의 추상메소드만 가지고 있어야한다는 것이다. 그리고 이런 인터페이스를 미리 함수적 인터페이스(@functionalInterface)라고 부른다.

즉, 함수구현 전용 인터페이스라고 부르는 것이다.

@ FunctionalInterface 어노테이션으로 이런 함수적 인터페이스를 명시 할 수 있다.

 

@FunctionalInterface인터페이스가 적용된 인터페이스는 한개의 추상메소드만 선언 할수 있게 된다.

1
2
3
4
5
6
7
8
//TestInterface.java
@FunctionalInterface
public interface TestInterface{
    public int plusAandB(int a, int b);
    
//  public int plusAll(int ...a);
//  컴파일 에러 발생
}
cs

@FunctionalInterface가 선언된 인터페이스에 추상메소드가 1개가 아니면 에러가 발생한다.

람다식 기본구조

람다식의 기본구조는 다음과 같다.

소괄호에는 구현한 함수의 인자를 그리고 화살표 다음에 중괄호에는 구현할 함수 몸체를 넣어주면 된다.

1
(타입 매개변수, ...) -> { 실행문;...};
cs

하지만 함수를 간편하고 쉽게 표현하기 위해서 람다는 많은 생략 기법을 사용한다.

  • 람다식 매개인자의 자료형은 생략가능하다.
  • 람다식의 매개인자가 한개인 경우 매개인자를 감싸는 소괄호를 생략 할 수 있다.
  • 람다식의 함수몸체에 실행문이 한개인 경우 함수의 몸체를 감싸는 중괄호를 생략 할 수 있다,
  • 람다식의 함수몸체에 실행문이 한개이고, 그 실행문이 return문일 경우 함수의 몸체를 감싸는 중괄호와 return을 생략 할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
InterfaceA1 a1 = (int a) -> {System.out.println("a:" + a);};
//매개인자 자료형 생략
InterfaceA1 a2 = (a) - > {System.out.println("a:" + a); };
 
InterfaceB1 b1 = (int a, int b) -> {System.out.println("a+b:" + (a + b));};
//매개인자 자료형 생략
InterfaceB1 b2 = (a, b) -> {System.out.println("a+b:" + (a + b));};
 
//매개인자가 하나뿐이라 소괄호 생략
InterfaceA1 a3 = a -> {System.out.println("a:" + a);};
//함수의 실행문이 한개라 중괄호를 생략
InterfaceA1 a4 = a -> System.out.println("a:" + a);
 
 
TestInterface t3 = a -> { return "a:" + String.valueOf(a); };
// 함수의 실행문이 한개이며, 리턴문만 있을경우 중괄호와 더불어 return문도 생략이 가능하다.
TestInterface t4 = a -> "a:" + String.valueOf(a);
 
 // 매개인자 없는 경우에는 빈 소괄호를 사용해야 한다.
InterfaceA1 a2 = () -> { System.out.println("인자가 없는 함수 구현"); };
cs

 


내용이 도움이 되셨거나 초보 블로거를 응원하고 싶으신 분은 아래 하트♥공감 버튼을 꾹 눌러주세요! 

내용의 수정이 있거나 도움이 필요하신 분은 댓글을 남겨주세요!




'Language > Java' 카테고리의 다른 글

예외 처리(Exception)  (0) 2019.03.21
컬랙션 프레임워크란?  (0) 2019.03.20
JVM 구조  (0) 2019.03.07
RxJava란? -4 Scheduler  (0) 2019.01.26
RxJava - 3 Operators 이어서  (0) 2019.01.26