번역가오현석

 

월애플베이직으로 코딩을 시작했으며, 10여년간 한국에서 개발자/팀장으로 재직 후, 현재는 호주 Griffith University에서 웹 개발자로 일하고 있다. 웹이나 모바일 등의 분야에서 값 중심의 프로그래밍을 통해 좀 더 오류 발생 가능성이 적고 유지보수가 편한 프로그램을 작성하는 방법과 이를 지원하는 여러 도구를 만드는 일에 관심이 많다.

 

원문링크

 

 

 

 

자바에서 람다 식이 필요한 이유  1


Why We Need Lambda Expressions in Java Part 1

 

람다식은 자바 8에 포함될 것이다하지만아직도 저항에 직면하고 있으며모든 자바 개발자가 유용성을 인정하고 있지도 않다특히 이들은 자바가 지닌 강력한 객체지향과 절차적 언어로서의 특성을 깨는 것이 아닌가 하는 두려움 때문에자바에 함수 언어의 특징을 추가하는 것이 실수가 될 것이라고 주장하곤 한다이 글의 목적은 바라건데 이런 의심을 없애고평이하면서 실용적인 예제를 통해 현대적 프로그래밍 언어라면 람다 식을 지원하지 않을 수 없음을 보여주는 데 있다.

 

외부 이터레이션과 내부 이터레이션

 

우선 아주 단순한 정수 리스트로부터 시작해 보자.


List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);                                                

 

이제 이 리스트의 모든 원소를 이터레이션하면서 출력하는 for 루프를 만들 수 있다


for (int number : numbers) {

    System.out.println(number);

}

 

위와 같은 문장은 아주 단순하고 흔한 것이다자바 개발자로 10년간 일하면서 하루도 이런 류의 코드를 작성하지 않은 날이 없다또 이 문장은 너무너무 단순한데.... 아니다그렇지 않다위와 같은 구문을 보면 내 2살바기 딸 소피아에게 놀고 나서 장난감을 치우게 하는 일이 떠오른다보통 다음과 같은 일이 벌어진다.


: "소피아, 장난감 정리하자. 땅에 어떤 장난감이 있지?"

소피아: ". 공이 있네"

: "그래. 공을 박스에 넣자. 땅에 또 뭐가 있지?"

소피아: ". 인형이 있지"

: "그래. 인형을 박스에 넣자. 땅에 또 뭐가 있지?"

소피아: ". 책이 있네"

: "그래. 책을 박스에 넣자. 땅에 또 뭐가 있지?"

소피아: "아니. 아무것도 없어"

: "잘했네. 이제 다 했다"

 

바로 이런 일을 우리가 매일 자바 컬렉션을 가지고 하고 있다하지만우리 대부분은 2살바기 꼬마가 아니다우리는 컬렉션을 외부에서 이터레이션하면서원소를 명시적으로 하나씩 꺼내서 처리하고 있다만약 소피아에게 단지 "소피아땅에 있는 모든 장난감을 박스에 넣으렴"이라 말할 수 있다면 훨씬 좋을 것이다이런 내부 이터레이션이 더 좋은 이유가 두가지 있다첫째로 소피아는 한손에 공다른손에 인형을 한꺼번에 나르기로 결정할 수도 있다두번째로박스에 가장 가까운 물건들을 먼저 나르고그 다음에 나머지를 옮기기로 할 수도 있다마찬가지로 내부 이터레이션을 사용하면 JIT 컴파일러가 원소 처리를 최적화 해서 병렬로 하거나 다른 순서로 하게 할 수도 있다자바나 다른 절차적 언어에서 하듯 외부에서 컬렉션을 이터레이션 하면 이런 방식의 최적화는 불가능하다.

 

그렇다면왜 내부 이터레이션을 사용하지 않을까내 생각은 이렇다자바 8 이전 버전에서는 이런 패턴에 대한 지원이 부족했다따라서 내부 이터레이션을 사용하려면 번잡하게(이름 없는 내부 클래스를 만들어야 한다기술해야 했다이로 인해 단순히 습관이 나쁘게 든 것뿐이다다음이 그 한 예이다.

 

numbers.forEach(new Consumer<Integer>() {

    public void accept(Integer value) {

        System.out.println(value);

    }

});


실제로는 forEach 메소드와 Consumer 인터페이스도 자바 8에 추가된 것이다하지만자바 5+에서도guava lambdaj와 같은 라이브러리를 사용해 이와 비슷한 일을 할 수 있다하지만 자바 8의 람다 식을 사용하면 다음과 같이 같은 작업을 더 간략하고 읽기 쉬운 방법으로 해낼 수 있다.


numbers.forEach((Integer value) -> System.out.println(value));


위 람다 식은 두 부분으로 이루어져 있다화살표(->)의 왼쪽은 매개변수 목록이고오른쪽은 몸체이다이 경우 자바 컴파일러가 람다식을 분석해 Consumer 인터페이스의 미 구현된 메소드(accept 메소드)와 동일한 타입(시그니쳐)인지 검사하고람다식을 마치 Consumer 인터페이스를 구현한 클래스의 인스턴스인 것처럼 사용한다물론 만들어진 바이트코드는 다를 수 있다람다 식의 인수의 타입 선언은 대부분의 경우 컴파일러가 추론할 수 있고다음과 같이 생략 가능하다.


numbers.forEach(value -> System.out.println(value));    // (1)


하지만이 문장도 자바 8에 포함될 메소드 참조(method reference)를 사용하면 더 간단하게 할 수 있다자세히 말하자면자바 8에 새로 도입될 :: 연산자를 사용하면 다음과 같이 정적 메소드나 인스턴스 메소드를 참조할 수 있다.


numbers.forEach(System.out::println);  // (2)


이렇게 하면함수 언어에서 에타(eta, 그리스어 η확장이라 알려진 과정에 의해컴파일러가 해당 메소드를 자동으로 "확장"해서 Consumer 함수형 인터페이스에 있는 유일한 추상 메소드와 같은 시그니처를 만들어주고그 결과 Consumer 인스턴스로 사용될 수 있게 된다.

 

(역주에타 확장(또는 더 일반적으로 에타 변환)이란 어떤 함수 f가 있을 때, (자바 람다식으로 표현하자면(x) -> f(x) f가 같다는 것입니다매개변수를 붙이면 에타 확장매개변수를 때어내면 에타 축소(reduction)이라 합니다다만f안에서 x가 자유변수(free variable)여야 합니다.

에타 확장이 실제 위의 forEach에서 어떤 일을 하냐 하면바로 그 앞의 식과 같은 일을 합니다위 식 (2)


numbers.forEach(System.out::println);


에서 System.out::println를 에타 확장하면(x) -> System.out::println(x)입니다따라서이는


numbers.forEach((x) -> System.out::println(x)) // (3)


이 됩니다x value로 바꾸면 위 식(3)은 식(1)과 완전히 동일한 식입니다.)

 

값만 전달하는 대신 작동 방식도 전달하기

 

앞의 예에서 본 것이 바로 람다 식이 유용한 가장 큰 이유이며어쩌면 유일한 이유이기도 하다람다식을 다른 함수에 전달할 수 있다면 값 뿐 아니라 작동 방식까지도 전달할 수 있다그렇게 되면 추상화의 수준을 극적으로 끌어 올릴 수 있으며더욱 일반적이며 유연하고 재사용 가능한 API를 만들 수 있다더 심화된 예를 살펴보면서 이런 주장을 입증할 것이다우선 일반적인 정수의 리스트로부터 시작해 보자.


List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);


리스트 안의 모든 정수의 합계를 내주는 메소드를 작성해 달라는 요청을 받으면다음과 같이 할 수 있다.


public int sumAll(List<Integer> numbers) {

    int total = 0;

    for (int number : numbers) {

        total += number;

    }

    return total;

}


다음날관리자가 우리 섹션으로 와서 사업부에서 리스트 안에 있는 짝수들만의 합도 요청했다고 말한다이런 요구를 가장 빠르게 처리할 방법은 무엇일까간단하다앞의 메소드를 복사해 붙여넣기 하고적당한 조건문으로 원소를 걸러내도록 하면 된다.


public int sumAllEven(List<Integer> numbers) {

    int total = 0;

    for (int number : numbers) {

        if (number % 2 == 0) {

            total += number;

        }

    }

    return total;

}


다른 어느 날다른 요구 사항이 또 도착한다이번에는 리스트의 원소를 더하되, 3보다 큰 수만을 더해야 한다이제는 어떻게 해야 할까물론다시 앞의 메소드를 복사해서 조건문의 식을 바꿀 수도 있다하지만그렇게 하는 것은 너무 지저분한 것 같다그렇지 않은가이제"우선 작성하고, 그 다음에는 복사하고, 세번째로는 리팩토링하자First Write, Second Copy, Third Refactor" 원칙에 따라 더 똑똑하게 일반적인 방식으로 처리할 수 없는지 고민해볼 때이다이 경우리스트와 함께 원소 합계를 구하기 전에 원소를 걸러내는 조건을 지정하는 Predicate(자바 8에서 추가된 또 다른 함수형 인터페이스)를 받는 고차(high order) 함수를 만들면 된다.


public int sumAll(List<Integer> numbers, Predicate<Integer> p) {

    int total = 0;

    for (int number : numbers) {

        if (p.test(number)) {

            total += number;

        }

    }

    return total;

}


다시 말하면데이터(정수의 리스트뿐 아니라그 데이터를 어떻게 사용할지에 대한 작동 방식(조건을 판단하기 위한 객체 Predicate)도 함께 메소드에 전달한다는 것이다이렇게 하면 앞의 세가지 요구 사항을 더 일반적인 재사용 가능한 메소드를 하나만 사용해서 충족시킬 수 있다.


sumAll(numbers, n -> true);

sumAll(numbers, n -> n % 2 == 0);

sumAll(numbers, n -> n > 3);


다음글(한글 번역은 다음주 등록 예정)서는 람다 식을 사용해 자바 코드가 더 간결하고 읽기 쉬워지는 경우를 몇 가지 보일 것이다.

 

 

저작자 표시 비영리 동일 조건 변경 허락
신고

설정

트랙백

댓글



저자 : Sonatype - 팀 오브라이언 정리

더보기

역자 : 장 선 진

더보기

644 페이지 

978-89-93827-23-1








Maven(메이븐)은 유대어로 지식의 축적자라는 뜻을 가지고 있다고 합니다.

메이븐의 특징을 간략하게 설명하자면, 라이브러리 의존성해결을 자동화해 주고 라이브러리 관리의 편의성을 증대시켜 준다고 할 수 있습니다.

조금 더 자세한 내용은 역자 머리말을 참고하기 바랍니다.

더보기



이 책은 메이븐을 만든 소나타입(Sonatype)에서 저술한 책입니다. 따라서 이 세상에 존재하는 그어떤 책보다도 메이븐에 대한 훌륭한 정보를 독자들에게 알려줄 것입니다

만약 아직까지 메이븐을 프로젝트에 본격적으로 도입하지 않았다면, 이번 기회에 메이븐을 도입하여 프로젝트를 효과적으로 관리하기를 적극 추천합니다엔터프라이즈 규모의 복잡한 프로젝트가 아니더라도 메이븐의 디펜던시 관리 기능을 한번만 사용하면 메이븐이 주는 효용이 얼마나 큰 지 바로 알 수 있기 때문입니다. 메이븐을 도입하는 것은 이제 선택이 아닌 필수입니다. 이런 면에서 이 책이 메이븐을 도입하고 사용하려는 분들에게 많은 도움이 되기를 희망합니다

저작자 표시 비영리 동일 조건 변경 허락
신고

설정

트랙백

댓글

Seam in Action

책 이야기 2010.03.17 15:13


저자: 댄 앨런

역자: 전준식, 최지웅, 최현덕

978-89-93827-18-7

 

혁신적인 Java EE 프레임워크인 Seam은 자바 기반 웹 개발을 재창조한다. 단순한 자바 객체와 미리 만들어진 위젯을 사용하고, XML을 거의 사용하지 않는 Seam의 직관적인 아키텍처와 API, 영속성을 적절히 관리하고, UI와 비즈니스 컴포넌트 둘 모두에 적용되는 단일 개발 방식을 제공한다. Seam은 모든 Java EE 컨테이너에서 동작하며 그것의 JSF 기반 접근방법은 Ajax를 매우 쉽게 구현할 수 있도록 해준다.

 

Seam In Action Java EE 개발자를 위한 Seam의 상세한 소개서이다. 이 책에서는 seam-gen을 사용하여 기본 애플리케이션을 생성하며, 예외 기반 설정, Java 5 어노테이션, aspect-oriented 프로그래밍을 통하여 Seam이 핵심 기능 이외의 작업들을 자동화하는 방법에 대해 설명한다. 여러분은 이 책을 통해서 스프링 통합, JavaScript 리모팅, 비즈니스 프로세스(jBPM)유상태 페이지 플로우(jPDL) 등을 위한 핵심 기술들을 마스터할 수 있다.

 

이 책의 내용

Seam-gen을 사용한 빠른 프로젝트 착수

Seam 어노테이션, 컴포넌트와 바이젝션(bijection) 이해

Seam의 새로운 영속성 모델 소개

ㆍ 리치 애플리케이션 만들기

목차보기

더보기

 

 

한국 독자에게

'Seam in Action’이 처음 출간된 이후로, 나는 수많은 개발자들로부터 이 책이 그들의 Seam에 대한 이해를 근본적으로 바꾸어 주었다는 이야기를 들었다. 그들은 Seam을 사용한 이후 개발 생산성을 크게 향상시킬 수 있었으며, 유일한 아쉬움은 그것을 좀 더 일찍 발견하지 못한 것이었다고 전했다. 이런 연락을 받을 때마다 내가 할 수 있는 것은 “그게 이 책을 집필한 이유입니다”라고 답변하는 것뿐이었다. 그리고 그것은 내가 여러분이 이 책을 읽기를 원하는 이유이기도 하다. 나는 여러분 또한 다른 개발자들이 Seam을 사용하면서 느꼈던 장점들을 느낄 수 있기를 바란다. 그런 의미에서, Seam In Action’내에 압축된 지식들이 전 세계로 확산되도록 하기 위해 이 책을 한국어로 출판하는 데 노력을 기울여준 동료들인 최지웅, 전준식, 최현덕 님께 감사의 말을 전한다. 나는 Seam 개발 초기 단계에서부터 그것을 사용했으며, Seam Java EE에서 빠져있는 퍼즐 조각들을 보충해 준다는 것을 알게 되었다. Seam Java EE 내에 존재하는 수많은 기술들 간의 간극을 메워준다. Seam JSF에서 직접 EJB를 호출할 수 있도록 해주거나 확장 영속성 컨텍스트를 적절하게 관리할 수 있도록 하는 등 Java EE 내에 존재하는 수많은 기술들의 간극을 메워주었다. Seam은 또한 개발자들이 가지고 있는 Java EE 개념들과 기술들에 존재하는 수많은 이론적인 한계 또한 지적해 준다. Seam을 공부하는 경우, 여러분은 단지 이 하나의 프레임워크만이 아닌(물론 그것만으로도 충분히 어렵다) Java EE 전반에 대해 배우게 되는 것이다. 이러한 이유로 Seam을 배우는 것이 개발자들에게는 매우 위협적으로 느껴지기도 한다. 나는 이러한 딜레마를 염두에 두고 이 책을 집필했다. 이 책은 JSF 라이프사이클에 대해 설명하고 그것의 단점을 지적한다. 이 책에서는 Facelets를 현실에 맞게 사용하는 방법에 대해 설명하고, 여러분이 영속성 컨텍스트에 대해 정확하게 이해할 수 있도록 하며, 그것을 적절하게 다루는 방법을 가르친다. 이 책은 EJB JNDI 이름들과 Seam이 그것을 어떻게 검색하는지 알기 쉽게 설명한다. 그리고 이 모든 핵심 개념들을 설명한 후, PDF 생성을 위한 iText나 비즈니스 프로세스 관리를 위한 jBPM 같은 서드 파티 통합 기능을 Seam에서 사용하는 방법을 익혀서 여분의 개발 스킬을 확장할 수 있도록 한다. 이 책의 독자들이 이 책을 가치 있는 것으로 느낀다면, 그것은 아마도 내가 여러분과 같은 입장에 있었기 때문일 것이다. 나 역시 Java EE의 모든 부분에 대해 배우려고 노력하고, Seam을 사용하여 그것을 어떻게 하나로 결합시킬 수 있을지 고민한 사람들 중 한명이었다. 이제 여러분의 모국어로 번역된 이 책을 읽으면서 Seam 애플리케이션을 보다 가치 있게 만드는 방법에 대해 배워보도록 하자.

 

Dan Allen(댄 앨런)

Senior Software Engineer

Red Hat, Inc.

그런데, SEAM은 무슨 뜻인가요? 자바와 관련된 용어의 약자일 것이라고 생각했는데, 이음새를 뜻하는 단어 외에는 그저 JBoss에 의해 개발된 웹 애플리케이션 프레임워크라고만 나와 있네요~ 궁금해요!!!

 

저작자 표시 비영리 동일 조건 변경 허락
신고

설정

트랙백

댓글


티스토리 툴바