람다가 등장한 배경
람다 표현식이 등장한 배경은 자바 8의 주요 개선 사항 중 하나이다. 이전 자바에서는 코드를 간결하게 표현하기 위해선 익명 클래스를 활용하였다. 익명클래스는 인터페이스나 추상 클래스의 구현을 정의하는 데에는 유용했지만, 코드가 복잡해지고 가독성이 떨어지는 문제가 발생되었다.
자바 8에서는 이러한 문제를 해결하기 위해 람다 표현식을 도입하였다. 람다 표현식은 익명 함수를 정의하는 간결한 방법으로, 함수형 프로그래밍 스타일을 지원하고 코드를 더 간결하게 만들어준다.
람다 표현식은 자바 컬렉션과 스트림 API와 밀접하게 관련되어 있으며, 컬렉션을 데이터를 저장하고 조작하는 데 사용되는 자바의 핵심 요소 중 하나이다. 자바 8에서는 이 컬렉션을 효과적으로 다루기 위해 스트림 API 도입하였고, 스트림이 컬렉션 요소를 처리하는 데 사용되는 것이 람다 표현식이다. 람다를 사용하면 스트림 연산을 간결하게 표현할 수 있다. 이를 통해 코드의 가독성과 유지보수성이 향상되었다.
따라서 람다 표현식은 자바의 익명 클래스보다 간결하고 가독성 높은 코드 작성에 도움을 주고, 자바 8에서 도입된 스트림API와 함께 사용되어 컬렉션 요소를 처리하는 방식을 혁신적으로 변화시켰다.(병렬처리)
병렬 처리란?
자바 컬렉션과 같이 다수의 요소를 포함하는 데이터가 있을 때, 이를 필터링, 정렬, 합산 등의 작업을 동시에 수행하는 것을 말한다. 즉, 여러 가지 연산을 동시에 처리하여 작업을 빠르게 수행하는 것이다.
람다식
람다식은 메서드를 하나의 식으로 표현한 것이다. 함수를 람다식으로 표현하게 되면 메서드의 이름이 필요없기 때문에, 람다식은 익명함수(AnonymousFuction)의 한 종류라고 볼 수 있다.
익명함수(Anonymous Fuction)란 함수의 이름이 없는 함수로, 익명 함수들은 모두 일급 객체이다. 일급 객체인 함수는 변수처럼 사용 가능하며 매개 변수로 전달이 가능하는 등의 특징을 가지고 있다.
기존의 방식으로 함수를 선언할 때는 다음과 같이 선언하였다.
// 기존의 방식
반환타입 메소드명 (매개변수, ...) {
실행문
}
// 예시
public String hello() {
return "Hello World";
}
하지만 람다를 활용하면 다음과 같이 괄호 () 와 화살표 -> 를 이용해 함수를 선언하게 된다.
// 람다 방식
(매개변수, ...) -> { 실행문 ... }
// 예시
() -> "Hello World!";
이렇게 람다식을 사용하게 되면 불필요한 코드를 줄이고, 가독성을 높아지게 된다. 그리고 함수형 인터페이스를 통한 일급 객체로 활용이 가능해지며, 이렇기 때문에 Stream API의 매개변수로도 활용이 가능하다.
람다식의 특징
람다식 내에서 사용되는 지역변수는 final이 붙지 않아도 effectively final로 간주된다. 이는 해당 변수의 값이 람다식 내에서 변경되지 않아야 한다는 것을 의미한다.
람다식으로 선언된 변수명은 중복될 수 없다.
람다식의 장점
- 코드를 간결하게 만들 수 있다.
- 개발자의 의도가 명확히 드러나 가독성을 높인다.
- 함수를 만드는 과정없이 한번에 처리할 수 있어 생산성이 높아진다.
- 병렬 프로그래밍이 용이하다.
람다식의 단점
- 람다를 사용하면서 만든 무명함수는 재사용이 불가능하다. 그러므로 동일한 기능을 여러 곳에서 사용해야 할 경우에는 별도의 메서드로 분리해야한다.
- 디버깅이 어렵다.
- 람다를 남발하면 비슷한 함수가 중복 생성되어 코드가 지저분해질 수 있다.
- 재귀로 만들 경우에 부적합하다.
람다식의 표현식
일반적인 람다의 표현식은 매개변수와 매개변수를 이용한 표현식으로 작성이 된다.
(매개변수, ...) -> {실행문 ...}
실행문이 한 줄일 경우 실행문의 생략할 수 있다.
(매개변수, ...) -> 실행문
실행문이 여러 줄 필요한 경우 { } 를 사용하여야 하며, 명시적으로 return를 입력해 준다.
(매개변수, ...) -> {실행문
...
return result;
}
함수형 인터페이스(Function Interface)
함수형 인터페이스란 단 하나의 추상 메서드를 가진 인터페이스를 의미한다. 단, 추상메서드가 하나만 존재한다면 여러개의 defalut 메서드와 static 메서드가 있어도 된다.
public interface FunctionalInterface {
// 단 하나의 추상메서드를 가지고 있어야 한다.
public abstract void doSomething(String text);
// default 메서드
default void a(){
...
}
// static 메서드
static void b(){
...
}
}
@FunctionalInterface 어노테이션
함수형 인터페이스는 @FunctionalInterface 어노테이션을 사용하여 표시 할 수 있다.
해당 어노테이션을 활용하지 않고도 추상 메서드가 하나이면 함수형 인터페이스로 활용 가능하다. 하지만 해당 어노테이션을 활용하면 명시적 표현이 가능해진다.
또, 함수형인터페이스에 대한 컴파일러 예외를 나타내주기 때문에 사용자 실수를 방지할 수 있다. 검증과 유지보수 측면에서 어노테이션을 사용하는 것을 권장한다.
그럼 함수형 인터페이스를 왜 사용할까?
함수형 인터페이스와 람다의 연관이 여기서 나온다. 자바의 람다식은 함수형 인터페이스로만 접근이 가능하다.
이 문장을 이해하기 위해선 자바의 특성을 간단하게 살펴볼 필요가 있다.
자바에서는 일급 시민(first class citizen)이라는 특징을 이용하여 객체를 정의하고 있다.
- 변수에 담는것이 가능하다
- 인자로 전달이 가능하다
- 반환값으로 전달이 가능하다.
하지만, 메서드 자체는 자바에서 일급값으로 취급하지 않는다. 그렇기 때문에 변수로 담지 못하고 인자로 전달하지 못하고 반환값으로 사용하지 못하는 이유가 있다.
기본적으로 함수형 프로그래밍의 익명함수는 일급객체이다. 그렇기 때문에 자바에서는 함수형 인터페이스를 통해 함수를 일급객체로 만들어 준다. 그렇기 때문에 람다식을 사용함으로써 함수형 인터페이스의 구현체를 코드의 일부로 직접 전달받을 수 있으며, 함수를 변수에 저장하고 전달하며, 함수의 반환값으로 사용할 수 있게 해 준다.
'Language > Java' 카테고리의 다른 글
[java] Arrays.asList() remove(), add() java.lang.UnsupportedOperationException 발생 (0) | 2024.07.31 |
---|---|
[java] 비트 연산자와 2진법 (0) | 2024.07.09 |
[인프런 워밍업 스터디 클럽 1기] 어노테이션의 역할 (0) | 2024.04.30 |
[스진초5기/Java] Overriding과 Overloading (0) | 2023.10.27 |
[Java] String[]을 List , List를 String[]로 변환하는 방법 (0) | 2023.10.24 |