엔지니어로 가는 길

JAVA 람다 표현식의 문법과 사용 본문

프로그래밍/Java

JAVA 람다 표현식의 문법과 사용

탐p슨 2020. 6. 23. 19:27
728x90

https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

 

이름이 없는 익명 클래스가 이름 있는 클래스보다 더 간결하지만 하나의 메소드만 갖는 클래스의 경우에는 익명 클래스조차 과하다. 람다 표현식을 이용하면 하나의 메소드만을 갖는 클래스의 객체를 익명 클래스보다 더 간결하고 분명하게 표현할 수 있다.

람다 표현식의 문법

 

 

-괄호로 속 콤마로 구분되는 형식 매개변수의 리스트

람다 표현식에서 매개변수의 데이터 타입을 생략할 수 있다. 또한 매개변수가 하나라면 괄호도 생략할 수 있다.

 

-arrow token: ->

 

-body: 단일 표현식이나 statement block

 

 

위와 같이 body가 단일 표현식으로 이루어진 경우 표현식을 계산한 뒤 결과를 리턴해준다. 아래와 같이 명시적으로 return statement를 사용할 수도 있다.

 

 

return statement는 표현식이 아니기 때문에 람다 표현식에서는 중괄호로 감싸주어야 한다. 하지만 void 메소드인 경우 중괄호로 감쌀 필요 없다.

 

 

람다 표현식은 메소드 선언과 닮아있다. 람다 표현식을 익명 메소드로 간주해도 좋다.

 

람다 표현식의 예시

 

 

-addition이라는 이름의 IntegerMath 구현체를 만들 때는 return statement를 사용하지 않았다. 람다 표현식에서 body에 단일 표현식이 올 경우 알아서 리턴해주기 때문이다.

-subtraction을 만들 때는 return statement를 사용해보았다. return statement는 표현식이 아니기 때문에 중괄호로 감싸주어야 한다.

-IntegerMath의 유일한 메소드인 operation의 매개변수가 두 개이므로 괄호로 꼭 감싸주어야 한다.

 

람다 표현식의 사용

 

특정 상황을 가정한 뒤 지역 클래스와 익명 클래스에서 시작하여 람다 표현식까지 개선시켜보자.

 

상황설명

 

Person 객체들이 List에 담겨 있고, 모든 Person 객체를 순회하며 어떤 일을 하고 싶다고 가정해보자. 가장 단순한 접근방법은 모두 다른 메소드를 만드는 것이다. 예를 들어 Person의 age가 특정 값 이상인 Person만 추출하고 싶다면 아래와 같은 메소드를 만드는 것이다.

 

 

이런 접근 방법으로 작성한 코드는 부서지기 쉽다. 예를 들어, Person 클래스의 구조를 바꾸어 다른 멤버 변수를 갖는 경우 이 변화를 수용하기 위해 API의 많은 부분을 다시 작성해야만 한다. 또한 이러한 접근은 쓸데없이 제한적이다. 예를 들어 특정 나이보다 더 어린 나이의 Person 객체를 출력하고 싶은 경우 어쩔것인가?

 

개선: 상한과 하한 받기

 

문제를 발견했으니 개선해보자. 보다 generic한 탐색 메소드를 만드는 것이다.

 

 

low와 high 값을 받아서 age의 값이 이 사이에 해당하는 경우만 출력하도록 구현이 바뀌었다.

printPersonsOlderThan보다는 generic하다. 하지만 성별이나 성별과 나이의 조합으로 특정 Person 클래스를 출력하고 싶은 경우라면 어떻게 할 것인가? 조금 더 고쳐보자. 기준을 명시하는 코드를 분리해내는 것이다.

 

개선: 기준을 인터페이스로 만들어 코드에서 분리해내기

 

 

CheckPerson이 특정 Person 객체를 골라낼 기준을 명시하고 있다. CheckPerson은 인터페이스로 아래와 같다.

 

 

 

이제 기준이 달라짐에 따라 코드를 수정할 필요 없이 구현체만 바꾸어주면 된다. 예를 들어 18~25세 남성을 출력하고 싶은 경우 아래와 같은 구현체를 만들 수 있다.

 

 

이때 printPersons는 다음과 같이 호출해야 한다.

 

 

기준을 명시하는 코드를 분리해내고 인터페이스로 만들어놓으니 이제는 Person 클래스의 구조를 변화시킨다고 해도 메소드를 다시 작성할 필요는 없어졌다. 하지만 아직도 개선의 여지가 남아있다. 현재의 코드에서는 탐색마다 새로운 인터페이스와 지역 클래스를 만들어야 하기 때문이다.

 

개선: 지역 클래스 대신 익명 클래스 사용

 

지역 클래스 대신 익명 클래스를 써보는 건 어떨까?

 

 

탐색을 만들 때마다 클래스를 만들 필요가 없기 때문에 코드의 양이 줄었다. 근데 익명 클래스의 문법은 인터페이스가 겨우 하나의 메소드만 가지고 있는 것에 비해 과하다.

 

개선: 람다 표현식 사용

 

이제 익명 클래스 대신에 람다 표현식을 고려해보자.

 

CheckPerson은 functional interface이다. functional interface란 단 하나의 추상 메소드만을 가지는 인터페이스를 말한다. 메소드가 하나이기 때문에 인터페이스를 구현할 때 구현하는 메소드의 이름을 생략할 수 있다. 메소드의 이름을 생략하기 위해서는 익명 클래스가 아닌 람다 표현식을 이용해야 한다.

 

 

개선: standard functional interface 사용

 

CheckPerson 대신 standard functional interface를 사용하면 코드의 양을 더 줄일 수 있다.

(standard functional interface의 예: Predicate, Consumer, Function ...)

 

 

 

 

위와 같이 이제 더이상 p가 Person임을 명시하지 않아도 된다.

 

다음엔 standard functional interface을 한 번 정리해봐야겠다.

728x90
Comments