지난번 포스팅에서는 람다(Lambda) 표현식이라는 간단하게 함수를 정의하는 개념에 대해 알아보았습니다.



이번 포스팅에서는 JAVA8 에서 이러한 람다를 지원할 수 있겠금 등장한 함수형 인터페이스에 대해 알아보려 합니다.


JAVA8에서는 새로운 어노테이션이 생겼습니다!!!!


@FunctionalInterface


어노테이션의 이름에서 다들 눈치를 체셨을 겁니다. 

네, 바로 함수형 인터페이스를 선언을 위해 등장한 어노테이션 입니다. (종류는 Built in annotation)


그렇다고 모든 interface에 저 어노테이션을 붙일 수는 없습니다. 

저 어노테이션이 오직 한 개의 추상메소드가 있는 인터페이스만 선언할 수 있습니다. 다음 아래와 같이 말이죠.


1
2
3
4
@FunctionalInterface
public interface CreateObjInterface {
    People createObject(int age, String name);
}
cs


왜 꼭 한개의 추상메소드를 가진 인터페이스만 선언이 가능하게 만들었을까요? 제가 읽고 있는 JAVA 8 IN ACTION 에서는 함수 형식을 표현하기 위해서라는 이유와 이미 많은 JAVA 프로그래머들이 추상 메소드 한개를 갖는 인터페이스에 익숙하기 때문이라고 합니다.


인터페이스에 여러 메소드가 정의되어야 한다면, 차라리 클래스로써, concrete 하게 가지고 있는게 더 좋겠죠. 이 것에 대한 내용은 아래 포스팅에 조금 더 자세히 적었습니다.



우리는 함수형 인터페이스를 사용하여 람다표현식을 사용할 수 있게 되었습니다. 앞서, 정의한 CreateObjInterface를 사용하여 다음과 같이 코드를 작성할 수 있습니다. 


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
32
33
34
35
36
37
38
/**
 * 사람의 정보를 저장하는 Vo 클래스
 * 
 * @author Doohyun
 *
 */
public class People {
    private int age;
    private String name;
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
}
 
// 객체 생성을 하는 방식의 람다식을 사용하여, 인스턴스를 생성
CreateObjInterface obj = (int age, String name) -> {
    People ret = new People();
    ret.setAge(age);
    ret.setName(name);
    return ret;
};
 
People doohyun = obj.createObject(27"남두현");
 
cs


여기에서 주목할 점은 람다표현식이 CreateObjInterface 인스턴스로 취급이 된다는 것입니다. (객체지향적으로 봤을 때는 interface를 구현(implement)하는 concrete 클래스를 만든 것이라고 할 수 있습니다.)


즉 이러한 특성을 이용해 함수를 인수로 가지고 있으며, 코드로 넘길 수 있는 것이 가능해졌다는 것을 알 수 있습니다.


이렇게, 람다를 사용하기 위해 함수형 인터페이스를 정의해야하는 이유는 사용할 람다의 시그니처가 되기 때문입니다. 시그니처란 파라미터 형식, 반환값 등을 말할 수 있는데요. (객체지향에서는 Access 수준, 메소드명, final 정도가 더있을 것 같습니다.람다가 어떻게 쓰일 것이다라는 규칙을 명시한 것이라 볼 수 있을 것 같습니다. 함수형 프로그래밍에서는 이것을 함수 디스크럽터 라고 합니다.


즉 람다가 익명의 추상 메소드라는 점에서, 기존 메소드 정의해야할 대부분을 똑같이 따라가줘야함을 알 수 있습니다. 그렇기 때문에 기존 익명 클래스 제작 시, 생겼던 규칙 역시 그대로 안고 갑니다.


1. checked exception

람다 내부에서 checked exception이 발생할 수 있는 로직의 경우, 해당 예외를 어떻게 처리를 할 것인지 명시해주어야합니다. 먼저 상위로 throw 하기 위해서는 아래와 같이 interface에 넘길 exception 명시를 해주어야 합니다. 


1
2
3
4
5
6
 
@FunctionalInterface
public interface CreateObjInterface throws NameEmptyException {
    People createObject(int age, String name);
}
 
cs


물론 람다 내에서 try-catch 문으로 처리가 가능합니다.


1
2
3
4
5
6
7
8
9
10
(int age, String name) -> {
    People ret = new People();
    try {
        ret.setName(name);
        ret.setAge(age);
    } catch (NameEmptyException e) {
        e.printStackTrace();
    }
    return ret;
};
cs


2. 변수 접근

기존 익명 클래스를 만들어 인터페이스를 제작했던 것 처럼 람다 역시 외부에 정의된 자유 변수(파라미터로 넘어가지 않는 변수)를 사용할 수 있습니다. 이와 같은 동작을 람다 캡처링이라고 부른다고 합니다. 


이러한 변수는 static 변수나 인스턴스 변수의 값을 자유롭게 변경할 수 있지만 지역변수 (함수 내부에 선언된 변수) 는 final인 상태로 밖에 가지고 있지 못합니다.


기존 자바에서는 익명 클래스 내부 구현 메소드에서 지역변수의 final을 강제화했지만 람다는 그렇지 않습니다. 람다의 경우 final 를 강제화 하지는 않지만 지역변수의 값을 변경 시 문법오류를 일으키게 됩니다.


이 것에 대한 자세한 포스팅은 람다와 함수형 인터페이스간의 해석 방법에 대한 포스팅에서 자세히 다루도록 하겠습니다.



자바 8 인 액션
국내도서
저자 : 라울-게이브리얼 우르마(RAOUL-GABRIEL URMA),마리오 푸스코(MARIO FUSCO),앨런 마이크로프트(ALAN MYCROFT) / 우정은역
출판 : 한빛미디어 2015.04.01
상세보기



반응형
Posted by N'

이번 포스팅은 함수형 프로그래밍의 꽃이라고 할 수 있는 람다 표현식에 대해 알아보려 합니다.


람다를 사용하는 이유는 계속 전 포스팅부터 봐왔지만 동작파라미터화를 통한 코드의 유연함을 가질 수 있도록 하고, 실행 시 유연하게 작동할 블록에 대하여 간결하게 만들자는 의미에서 등장했습니다.


동작파라미터화가 무엇인지 모른다면? 이곳으로 가서 먼저 보시길 ㅎㅎ



일단 람다(Lambda)가 무엇일까요?


람다는 미적분학의 기호 중 λ (람다 대수)에서 유래되었습니다. 이 것은 함수 정의, 함수 적용, 귀납적 함수를 추상화한 형식 체계를 나타내는데요. 이 뜻대로, 람다가 JAVA8에 구현되었습니다. (익명 클래스를 대체하여, 추상메소드를 전달한다는 점에서 비슷한 것 같네요. ㅡㅡ^)


람다 표현식은 메소드로 전달하는 익명 함수를 단순화 시킨 것으로, 파라미터 리스트, 반환 형식, checked exception 등 기존 메소드 정의 시 해야 했던 것을 모두 해야합니다. JAVA8 IN ACTION에서는 람다의 특징을 다음과 같이 정의했습니다.


1. 익명

보통의 메소드와 달리 이름이 없으니 익명입니다. 


2. 함수

클래스에 종속되는 메소드와 달리 함수라고 부릅니다.


3. 전달

매개변수로 전달이 가능합니다. 또한 함수를 변수에 저장할 수 있습니다. 

(자바가 자바스크립트 처럼 되어가네요. 이렇게요.)


1
2
3
var func1 = function() {
    console.log('변수로 가지고 있는 함수입니다.');
}
cs


4. 간결성

이건 뭐, 너무 언급해서... 굳이 객체로 감싸지 않아도 됩니다.



람다는 크게 세 부분으로 나누어져 있습니다. (파라미터 리스트, 화살표, 바디)

파라미터 리스트는 말 그대로 매개변수 정의부, 바디는 메소드의 바디, 화살표는 파라미터 리스트와 바디를 연결해주는 것을 말합니다.


(parameter) -> expression 


이라 보면 됩니다. expression이 길어진다면 {}을 붙일 수 있습니다.


람다를 통해서, 보통 다음과 같은 일을 할 수 있습니다.


1. boolean 표현식 

아래는 파라미터 한개를 받아, boolean을 표현합니다.


1
(int a) -> a > 5
cs


2. 객체 생성

아래는 나이와 이름을 받아, People 인스턴스를 만들고 있습니다.


1
2
3
4
5
6
 (int age, String name) -> {
            People ret = new People();
            ret.setAge(age);
            ret.setName(name);
            return ret;
        };
cs


3. 객체 소비 (프로시저)

보통 void 함수와 같은 역할이라 보면 됩니다.


1
2
3
 (People people) -> {
            System.out.println(people.toString());
        };
cs


4. 객체에서 선택/추출

객체에서 특정 내용을 추출합니다. (people 객체에서 나이를 선택해서 뽑아냅니다.


1
 (People people) -> people.getAge()
cs


5. 두 값을 조합

객체에서 두 값을 조합한 결과를 출력합니다.


1
(int a, int b) -> a + b
cs


6. 두 값을 비교

두 값을 비교한 결과를 출력합니다.


1
(int a, int b) -> a >= b
cs


보통 위와 같은 6가지 패턴으로 주로 사용하고 있으며, 이러한 방법들은 우리가 보통 함수를 만들고 사용하던 방식과 차이가 없어보입니다. (즉 처음 프로그래밍을 배우기 시작하며, 함수라는 개념을 배우던 그 때로 돌아간 것이라 볼 수 있네요. ㅡㅡ^)


다음 포스팅에서는 JAVA8 에서 람다 표현식에 개념과 함께 등장한 함수형 인터페이스와 편의성을 위해 미리 구현된 몇가지의 인터페이스를 보고자 합니다.





자바 8 인 액션
국내도서
저자 : 라울-게이브리얼 우르마(RAOUL-GABRIEL URMA),마리오 푸스코(MARIO FUSCO),앨런 마이크로프트(ALAN MYCROFT) / 우정은역
출판 : 한빛미디어 2015.04.01
상세보기

 

반응형
Posted by N'

이번 포스팅에서는 지난번에 포스팅했던 함수형 프로그래밍을 통한 방법과 기존의 객체지향 관점의 디자인 패턴과 비교를 해보고자 합니다.



이 포스팅을 올리려고 생각한 이유는 현재 보고 있는 책인 "JAVA8 IN ACTION" 에서는 메소드를 코드로 넘기는 것을 통해 간단히 동작 파라미터화를 하는 것을 보여줌으로써, 기존의 전략 패턴을 사장시킬 수 있을까에 대한 생각이 들었습니다.


하지만 꼭 그런 것은 아닌 경우가 몇가지가 있었습니다.


1. 전략 자체가 상태를 가지고 있어야 하는 경우.


보통 전략 패턴을 사용하여, 전략 객체를 만들 때, 필자의 경우에는 


* 전략이 상태를 가지고 있는 경우라면, interface를 만들고 concrete class 를 구현

* 전략이 상태를 가지지 않는 경우라면, enum을 사용해 singleton 으로 생성


으로 구현하였습니다.


함수형 프로그래밍에서 사용하는 메소드 역시, 특정 상태를 저장한 체로 유지할 수 없으며, 이는 상태가 필요한 전략에서는 사용할 수 없음을 말할 것 같습니다. 


2. 전략 자체가 구현해야할 추상 메소드가 다수 있는 경우.


AppleFilter 예제에서는 간단히 필터의 역할만을 Predicate 인터페이스를 통해 함수 자체로 넘기는 것이 가능했지만 구현해야할 메소드가 다수라면 기존 전략 패턴을 사용해야 할 것으로 보입니다.


물론 기능단위로 더욱 쪼개거나, 동작을 파라미터로 더 받을 수도 있겠지만, 아래 UML과 같이 한 전략에 대해서 각 구현 클래스가 concrete하게 가지고 있는 것이 유지보수성에서 더 좋아보입니다. 특히 한 전략에 대해서 해야할 다른 일들이 늘어난다면 더욱 이 방법을 해야할 것 같습니다. ㅡㅡ^.



아직 모든 장을 만나본 것은 아니지만, 간단하게 처리할 수 있는 비지니스 로직은 함수형프로그래밍으로, 보다 재사용성이 높고 복잡도가 있는 작업은 기존 객체지향적인 사고가 필요하지 않을까라는 생각이 드네요. 

(아직 책에서 이야기하는 함수형 사고가 안길러져서 그런 걸 수도 있습니다. ㅡㅡ^)



자바 8 인 액션
국내도서
저자 : 라울-게이브리얼 우르마(RAOUL-GABRIEL URMA),마리오 푸스코(MARIO FUSCO),앨런 마이크로프트(ALAN MYCROFT) / 우정은역
출판 : 한빛미디어 2015.04.01
상세보기


반응형
Posted by N'