람다 표현식이란?
해당 Post는 람다 표현식에 대해서 정리한 파일입니다.
람다 표현식(Lamda Expression)이란
2014년에 발표된 자바의 버전인 Java SE 8 버전에서는 많은 사항이 변경되거나 새롭게 추가되었습니다.
그 중 람다 표현식은 간단히 말해 메소드를 하나의 식으로 표현한 것입니다.
즉, 식별자 없이 실행할 수 있는 함수 표현식을 의미하며, 따라서 익명 함수(anonymous function)라고도 부릅니다.
클래스를 만들고 객체를 생성하지 않아도 메소드를 사용할 수 있습니다.
또한, 람다 표현식은 메소드의 매개변수로 전달될 수도 있고, 메소드의 결괏값으로 반환될 수도 있습니다.
Java SE 8 버전부터는 람다 표현식을 사용하여 자바에서도 함수형 프로그래밍을 할 수 있게 되었습니다.
함수형 프로그래밍 : 함수형 프로그래밍은 순수 함수를 구현하고 호출함으로써 외부 자료에 부수적인 영향을 주지 않도록 구현하는 방식입니다.
순수 함수란 매개변수만을 사용하여 만드는 함수이다.
즉 함수 내부에서 함수 외부에 있는 변수를 사용하지 않아 함수가 수행되더라도 외부에 영향을 주지 않는다.람다 표현식의 장,단점
장점 : 기존의 불필요한 코드를 줄여주고, 작성된 코드의 가독성을 높일 수 있습니다.
단점 : 디버깅하기 힘들어질 수 있습니다.
람다 표현식의 형식
(parameters) -> expression 또는 (parameters) -> { statements; }
여기에 몇가지 구분이 됩니다.
-
매개변수의 타입을 추론할 수 있는 경우에는 타입을 생략할 수 있습니다.
-
매개변수가 하나인 경우에는 괄호(())를 생략할 수 있습니다.
-
함수의 몸체가 하나의 명령문만으로 이루어진 경우에는 중괄호({})를 생략할 수 있습니다. (이때 세미콜론(;)은 붙이지 않음)
-
함수의 몸체가 하나의 return 문으로만 이루어진 경우에는 중괄호({})를 생략할 수 없습니다.
-
return 문 대신 표현식을 사용할 수 있으며, 이때 반환값은 표현식의 결괏값이 됩니다. (이때 세미콜론(;)은 붙이지 않음)
간단한 예시를 봅시다.
int min(int x, int y) {
return x < y ? x : y;
}
위의 예제 메소드를 람다 표현식으로 표현하면,
(x, y) -> x < y ? x : y;
이렇게 줄어드는 것을 확인할 수 있습니다.
그런데 자바에서는 클래스의 선언과 동시에 객체를 생성하므로, 단 하나의 객체만을 생성할 수 있는 클래스를 익명 클래스라고 합니다.
따라서 자바에서 람다 표현식은 익명 클래스와 같다고 할 수 있습니다.
지난 번에 보았던 섬 연결하기 문제의 코드를 꺼내봅시다.
import java.util.*;
class MyComparator implements Comparator<int[]>{
@Override
public int compare(int[] o1, int[] o2){
return o1[2]-o2[2];
}
}
class Solution {
static int[] parent;
public int solution(int n, int[][] costs) {
int answer = 0;
make(n);
Arrays.sort(costs, new MyComparator());
for( int[] cost : costs ) {
int from = cost[0];
int to = cost[1];
int weight = cost[2];
if( isConnect(from,to) ) continue;
else {
answer+=weight;
union(from,to);
}
}
return answer;
}
private static void make(int n)
{
parent = new int[n];
for(int i=0; i<n; i++) {
parent[i]=i;
}
}
private static int Find(int index) {
if(parent[index]==index) return index;
return Find(parent[index]);
}
private static void union(int from, int to) {
from = Find(from);
to = Find(to);
if( from < to ) parent[from] = to;
else parent[to] = from;
}
private static boolean isConnect(int from, int to) {
from = Find(from);
to = Find(to);
return from==to;
}
}
이 중에서 윗 부분만 잠깐 봅시다.
import java.util.*;
class MyComparator implements Comparator<int[]>{
@Override
public int compare(int[] o1, int[] o2){
return o1[2]-o2[2];
}
}
class Solution {
static int[] parent;
public int solution(int n, int[][] costs) {
int answer = 0;
make(n);
Arrays.sort(costs, new MyComparator());
이 부분은 Comparator를 사용하기 위해서 MyComparator를 만들어서 compare를 이용해 정렬 방식을 정해주는 형식이었습니다.
여기에 람다식을 적용한다면 아래와 같이 바뀌게 됩니다.
class Solution {
static int[] parent;
public int solution(int n, int[][] costs) {
int answer = 0;
make(n);
Arrays.sort(costs,(o1,o2)->{
return o1[2]-o2[2];
});
확실히 코드가 많이 줄어들었다는 것을 확인할 수 있습니다.
함수형 인터페이스(functional interface)
람다 표현식을 사용할 때는 람다 표현식을 저장하기 위한 참조 변수의 타입을 결정해야만 합니다.
자바에서는 참조 변수 없이 메서드를 호출할 수 없기 때문에 함수형 인터페이스를 만들고 인터페이스에 람다식으로 구현할 메서드를 선언합니다.
참조변수의타입 참조변수의이름 = 람다 표현식
위의 문법처럼 람다 표현식을 하나의 변수에 대입할 때 사용하는 참조 변수의 타입을 함수형 인터페이스라고 부릅니다.
함수형 인터페이스는 추상 클래스와는 달리 단 하나의 추상 메소드만을 가져야 합니다.
(인터페이스에 실수로 다른 메서드를 추가할 수 있는데, 이를 방지하기 위해서 @FunctionalInterface 어노테이션 사용)
위와 같은 어노테이션을 인터페이스의 선언 앞에 붙이면, 컴파일러는 해당 인터페이스를 함수형 인터페이스로 인식합니다.
자바 컴파일러는 이렇게 명시된 함수형 인터페이스에 두 개 이상의 메소드가 선언되면 오류를 발생시킵니다.
아래의 예시를 봅시다!
@FunctionalInterface
interface lambdaTest { // 함수형 인터페이스의 선언
public int sum(int x, int y);
}
public class Main2 {
public static void main(String[] args){
lambdaTest sumResult = (x, y) -> x + y; // 추상 메소드의 구현
System.out.println(sumResult.sum(3, 4)); // 함수형 인터페이스의 사용
}
}
참고 사이트는 TCPSchool 입니다!
부족한 부분이 있다면 댓글 남겨주세요!