람다식(Lambda Expression)
람다식은 JDK1.8부터 추가된 개념이며, 람다식의 도입으로 자바는 객체지향언어인 동시에 함수형 언어가 되었다.
람다식은 간단히 말해서 메소드를 '하나의 식'으로 간결하게 정의하고 전달할 수 있게 해주는 문법적 구조이다.
메소드를 람다식의 문법 구조로 작성하면 메소드의 이름과 반환 값이 생략되므로, 람다식을 '익명 함수(anonymous function)'라고 표현하기도 한다.
*참고* 함수형 언어란? 프로그래밍 패러다임 중 하나로, 프로그램을 수학적인 함수처럼 다루는 방법이다.
여기서 함수는 '입력'을 받아 '출력'을 만들어내는 작은 부분의 코드 조각이며, 이 조각들을 결합해서 더 큰 프로그램을 만드는 것을 함수형 프로그래밍이라고 말한다.
예를 들어, 두 정수를 입력 받아 더한 값을 출력으로 반환해주는 함수가 있다고 가정한다. 이러한 함수는 항상 "같은 입력"에 대해 "같은 출력"을 생성하므로 "순수 함수"라고 말한다.
즉, 함수형 프로그래밍에서는 이러한 작은 함수(순수 함수)들을 조합해서 복잡한 작업을 수행하는 프로그래밍 스타일을 의미한다.
*참고* 메소드와 함수의 차이? 프로그래밍에서의 함수라는 명칭은 수학에서 유래된 것이다. 수학의 함수와 개념이 유사하기 때문이지만, 객체지향개념에서는 함수 대신 객체의 행위나 동작을 의미하는 메소드라는 용어를 사용한다. 일반적으로는 메소드와 함수는 동의어로 취급되지만, 자바에서는 특정 클래스에 반드시 속해야 한다는 제약이 있기 때문에 기존의 함수와 동의어인 메소드를 선택해서 사용한 것이다. 그러나 람다식의 도입으로 메소드가 하나의 독립적인 기능을 하기 때문에 함수라는 용어를 표현하게 된 것이다.
람다식의 작성 방법
'익명 함수'라고도 표현되는 람다식은 메소드에서 이름과 반환타입을 제거하고 매개변수 선언부와 몸통{} 사이에 화살표 -> 를 추가한다.
*일반적인 메소드 선언*
반환타입 메소드이름 (매개 변수){
}
*람다식*
반환타입 메소드이름 (매개 변수) ->{
}
반환값이 있는 메소드의 경우, return문 대신 '식'으로 대신할 수 있다. 식의 연산결과가 자동적으로 반환값이 된다.
람다식에서는 추론 가능한 경우면 문법 구조를 생략하는 것이 가능하며, 아래는 추론 가능한 것을 생략한 예제이다.
*참고* 람다식에서 추론 가능한 경우라는 것은, 해당 문법을 명시적으로 작성하지 않아도 컴파일러에 의해 해당 표현식을 분석하고 추론하여 생략 가능하게끔 만들어 주는 것을 의미한다. 이는 Java 8부터 도입된 기능 중 하나로, 코드를 보다 간결하게 만들어준다.
(int x) -> (return x+1);
(int x) -> x+1; // 중괄호 안의 문장이 하나인 경우 생략 가능
(x) -> x+1; // 매개변수의 타입이 추론 가능한 겨우로 매개변수 타입 생략 가능
x -> x+1 // 매개변수가 하나인 경우 소괄화 생략 가능
위 예시와 같이 추론 가능한 것은 모두 생략이 가능하며, 코드가 보다 더 간결해진 것을 확인할 수 있다.
다음은 람다식을 활용한 간단한 예제이다.
1번) 예제
interface MyInterface{ // 인터페이스 생성
int method(int x);
}
public class LambdaExample {
public static void main(String[] args) {
MyInterface if1 = x-> x+1; // 익명 클래스를 활용하여 인터페이스를 간단히 구현함.
System.out.println(if1.method(1)); // 익명 클래스의 메소드 호출
}
}
위 예시에서 보이는 바와 같이 람다식을 활용하여, 단 몇줄의 코드만으로 인터페이스를 구현한 익명 객체를 생성했다.
기존의 방식대로라면, 아래와 같은 방법으로 작성됐을 것이다.
2번)예제
interface MyInterface{ // 인터페이스 생성
int method(int x);
}
class MyClass implements MyInterface { // 인터페이스 구현
public int method(int x){ // 인터페이스 메소드 구현
return x+1;
}
}
public class LambdaExample{
public static void main(String[] args) {
MyClass c = new MyClass();
c.method(1);
}
}
클래스를 명시적으로 작성한 2번 예제 코드보다 람다식을 활용한 1번 예제가 간결하면서도 이해하기 쉽다는 것에 이견이 없을 것이다.
2번 예제를 살펴보면, 모든 메소드는 클래스에 포함되어야 하므로 클래스도 새롭게 만들어야 하고 객체도 생성해야만 비로소 메소드를 호출할 수 있다는 번거로움이 있다.
그러나 람다식은 이러한 모든 과정 없이 오직 람다식 자체만으로도 메서드의 역할을 대신할 수 있게 된 것이다.
*참고* 람다식 내에서 참조하는 지역변수는 'final'이 붙지 않았어도 상수로 간주된다. 즉, 일관성을 위해서 람다식 내에서 지역변수를 참조하게되면 해당 지역변수는 람다식 내에서나 외부, 어느 곳에서도 이 변수들의 갑슬 변경하는 것을 허용하지 않는다.
정리
람다식의 주요 특징과 구문에 대해 정리하자면 아래와 같다.
1. 람다식은 이름이 없는 익명 함수를 정의하는 방법이다.
2. 람다식은 입력 매개변수를 가질 수 있으며, 필요한 경우 여러 개의 매개변수를 정의할 수 있다.
3. 람다식은 매개변수와 함수 본문을 화살표( -> )로 구분하며, 화살표 왼쪽에는 매개변수가 오고, 오른쪽에는 본문이 위치한다. 이때, 컴파일러에 의해 추론 가능한 표현식은 생략이 가능하다.
4. 람다식 내에서 참조하는 변수는 final이 붙지 않아도 상수로 간주되며, 람다식 내에서 참조되는 순간 해당 변수는 어느 곳에서도 값을 변경할 수 없다.
5. 함수의 본문은 매개변수를 이용하여 원하는 연산을 수행하고 결과를 반환한다.
'Java > 람다와 스트림' 카테고리의 다른 글
스트림(stream) - 기본 (0) | 2023.09.25 |
---|---|
java.util.function 패키지 (0) | 2023.09.13 |
(람다식) 함수형 인터페이스와 메소드 레퍼런스 (0) | 2023.09.05 |