정보공간_1

[5기 부산 정우진] 람다표현식(Lambda Expressions)과 클로저(Closure) 본문

IT 놀이터/Elite Member Tech & Talk

[5기 부산 정우진] 람다표현식(Lambda Expressions)과 클로저(Closure)

알 수 없는 사용자 2014. 4. 24. 13:36
지난 jdk7 이 발표 되기전 많은 사용자들은 자바 진영에서도 람다 표현식(Lambda Expressions)을 도입 할 것이란 예상을 했었습니다. 하지만 2년이 지난 최근에서야 jdk8에 람다 표현식을 도입 하였는데 본 블로그에서는 jdk8에 새롭게 추가된 람다 표현식의 간단한 사용 예제와 람다 표현식과 밀접한 관련이 있는 클로저를 알아 봅니다. 


우선 람다 표현식은 전혀 새로운 개념이 아닌 이미 c#은 delegate라는 대리자를 통해 람다 표현식을 지원 하였으며 이후 java 진영보다 먼저 세련된 방식의 람다 표현식을 지원하였습니다. 그렇다면 람다 표현식이 정확히 무엇을 뜻하는 걸까요?


람다 표현식은 별도의 장소에서 미리 선언하지 않고 필요한 곳에서 바로 구현 할 수 있는데 이 표현방식은 코드를 좀더 짧고 간결하게 나타낼 수 있다는 장점이 있습니다. 


jdk8 이전에도 별도의 인스턴스 생성없이 메소드를 작성 할 수 있는 방법은 있었으며 이미 널리 쓰이고 있었던 방법이 있었습니다. 바로 익명 클래스(Anonymous Class)를 이용하여 메소드를 작성하는 방법 인데 익명 클래스와 람다 표현식을 이용한 두 개의 코드를 비교해 보겠습니다. 


Person  클래스는 사용자의 성별과 이름, 나이, 생년월일을 저장하고 있으며 각각의 값을 리턴해주는 메소드로 구성되어 있다. http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/java/javaOO/examples/Person.java


    interface CheckPerson { boolean test(Person p); } public static void printPersons(List<Person> roster, CheckPerson tester) { for (Person p : roster) { if (tester.test(p)) { p.printPerson(); } } } public static void main(String...args){ List<Person> roster = Person.createRoster(); printPersons(roster, new CheckPerson() { public boolean test(Person p) { return p.getGender() == Person.Sex.MALE &&          p.getAge() >= 18 && p.getAge() <= 25; } }); }

    위 코드는 기존에 흔히 쓰는 익명 클래스로 통해 별도의 인스턴스 생성없이 메소드를 오버라이딩 하는 방법 입니다.  코드의 내용은 Person 타입의 boolean값을 리턴하는 CheckPerson 인터페이스를 구현하여 Person의

     Sex가 MALE이고 Age가 18과 25 사이인 사용자를 프린트하는 코드 입니다. 


    그렇다면 익명 클래스를 사용한 printPersons 메소드를 람다 표현식으로 바꾸면 아래와 같습니다.  


    printPersons(roster, (Person p) -> p.getGender() ==                                 
    Person.Sex.MALE  && p.getAge() >= 18 && p.getAge() <= 25);


    익명 클래스를 사용 했을때 보다 훨씬 간결해진 코드의 모습을 확인 할 수 있습니다. 

    위의 익명 클래스 외에도 로컬 클래스(Local Class)역시 람다 표현식을 이용해 간결하게 표현 할 수 있습니다. 


    jdk8에서 비로소 도입된 람다 표현식은 클로저(Closure)와 밀접한 관련이 있는데 클로저는 ‘닫힘’을 뜻하는 단어입니다.




      





    오른쪽 그림을 살펴보면 바깥에서 선언된 n과 같은 변수에 접근 할 수 있으면 작은 원 내부를 클로저라부릅니다. 특별할 것이 없는 이 설명에서 자바에서는 이미 클로저를 지원하고 있다고 생각 할 수 있는데 아래의 코드를 봅시다.








    public void event_Click() {
    	final int i = 1;
    	JButton button = new JButton(“Click”);
    	button.addActionListener(new ActionListener() {
    		public void actionPerformed(ActionEvent e) {
    			System.out.print(“Number n = “ + n);
    	});
     }

    흔히 보는 Button 이벤트를 구현하는 코드로 버튼을 눌렀을때 n의 값인 1이 출력 된다는 것은 누구나 알 수 있는 사실 입니다. 위의 그림과 비교해 보면 큰원은 event_Click 메소드에 해당하며 ActionListener를 구현하고 있는 익명클래스는 작은 원에 해당 합니다


    그렇다면 이미 자바에서는 클로저를 지원 하고 있다고 생각 할 수 있는데 여기에는 한가지 문제점이 있습니다.바로 final 키워드 입니다. 자바는 변경가능한 자유변수를 허용하지 않기 때문에 final 키워드 없이는 컴파일 되지 않습니다. 클로저는 일반적으로 자유롭게 접근이 가능하기 때문에(클로저를 지원하는 c#은 자유롭게 변경가능)익명 클래스를 클로저와 같다고 하는 것에는 조금 무리가 따릅니다. 


    클로저를 이용한 람다 표현식은 좀더 풍부하고 간결한 표현이 가능하다는 점에서 자바의 이런 제약은 아쉬움이 남을 수 있지만 자바의 핵심 패러다임인 ‘단순함’을 해칠 수 있다는 생각과 자바 커뮤니티의 리더중 한명이 조슈아 블로흐 역시 클로저를 지원하게 되면 자바의 타입 시스템에 큰 변화를 줘야 하며 자바의 복잡성의 수준을 더 높게 끌어 올려야 한다고 말했던 만큼 그 나름의 이유가 있다고 할 수 있습니다.


    • 본 내용은  "The Java Tutorials" 의 소스코드와 내용을 참조 하였음.