[JAVA] 람다식

용용학생·2024년 5월 6일

자바

목록 보기
23/32

람다식이란?

  • 메소드를 하나의 식(expression) 으로 표현한 것
  • 메소드를 람다식으로 표현하면 메소드의 이름과 반환 타입이 없어지므로,
    익명 함수라고도 함
  • JDK 1.8 에서 도입된 자바 언어의 큰 변화 중 하나
  • 람다식의 도입으로 인해, 객체지향 언어인 자바가 함수형 언어의 기능도 가짐

람다식 작성

람다식은 익명 함수답게 메소드에서 이름과 반환 타입을 제거하고
매개변수 선언부과 메소드 몸통{ } 사이에 ->를 추가한다.

//	일반 메소드 :
	반환타입 메소드이름(매개변수 선언) {
    	문장들
    }
    
//  람다식으로 작성 :
    (매개변수 선언) -> {
    	문장들
    }

예를 들어, 두 값 중 큰 값을 반환하는 메소드 max를 람다식으로 변환하면 이렇게 된다.

//  일반 메소드 : 
	int max(int a, int b) {
    	return a > b ? a : b;
    }
    
//  람다식으로 작성 :
	(int a, int b) -> {
    	return a > b ? a : b;
    }

람다식 문법

  • 반환 값이 있는 메소드의 경우, return문 대신 식(expression) 으로 대신 할 수 있다. 이 때 문장 이 아닌 이므로 끝에 ;를 붙이지 않는다.
	(int a, int b) -> { return a > b ? a : b; }
    
    // return문 생략
    (int a, int b) -> a > b ? a : b
  • 매개변수의 타입이 추론이 가능하다면 생략이 가능하다. 대부분의 경우 추론이 가능하기 때문에 생략이 가능하다.
    반환타입이 없는 이유도 항상 추론이 가능하기 때문이다.
	(int a, int b) ->  a > b ? a : b 
    
    // 매개변수의 타입 생략
    (a, b) -> a > b ? a : b
  • 매개변수가 하나뿐인 경우에는 괄호( )를 생략할 수 있다.
    단, 타입이 있으면 생략할 수 없다.
	(a) -> a * a
    (int a) -> a * a
    
    // 괄호( ) 생략
    a -> a * a
    int a -> a * a // 에러. 매개변수의 타입이 있음
  • 괄호{ } 안의 문장이 하나라면 생략할 수 있다. 이 때, 문장의 끝에 ;를 붙이지 않는다.
	(int a) -> { System.out.println("a : " + a); }
    
    // 괄호{ } 생략
    (int a) -> System.out.println("a : " + a)
  • 괄호{ } 안의 문장이 return문일 경우는 괄호{ }를 생략할 수 없다.
	(int a, int b) -> return a > b ? a : b   // 에러. return문은 괄호 생략 X

함수형 인터페이스

타입 f = (int a, int b) -> a > b ? a : b

위의 람다식을 보자면, 람다식을 그저 변수의 값으로 선언하는 것처럼 보인다.
그러나 자바에서 메소드는 단독으로 선언될 수 없다. (클래스에 포함되어 있어야 한다)

객체를 통해 메소드를 호출해야 하는 것처럼 람다식도 이름이 없는 객체를 통해 호출되는 것이다.

정확히 말하면 인터페이스의 익명 구현 객체로 표현한 것이다.


예를 들어, max라는 메소드가 정의된 MyFunction 인터페이스가 있다고 가정하자.

interface MyFunction {
	public abstract int max(int a, int b);
}

그러면 이 인터페이스를 구현한 익명 클래스의 객체는 다음과 같이 생성할 수 있다.

	MyFunction f = new MyFunction() {
    					public int max(int a, int b) {
                        	return a > b ? a : b;
                        }
                   }; // 익명 클래스는 끝에 세미콜른을 붙여 주어야 함
                   
    int big = f.max(3, 5); // 익명 객체의 메소드 호출

MyFunction 인터페이스의 메소드를 구현과 동시에 구현한 클래스의 객체를 생성!!
이를 익명 구현 객체라고 한다.

인터페이스의 max 메소드는 람다식과 선언부가 일치한다. 그래서 위 코드를 람다식으로 대체할 수 있다.

	MyFunction f = (int a, int b) -> a > b ? a : b;
    
    int big = f.max(3, 5);

익명 객체를 람다식으로 대체 가능한 이유

위에서 익명 객체를 람다식으로 대체 가능한 이유는
실제로는 람다식도 익명 객체이고, MyFunction 인터페이스를 구현한 익명 객체의 메소드 max()와 람다식의 매개변수 타입과 개수 그리고 반환값이 일치하기 때문이다.

함수형 인터페이스(Functional Interface)

위의 인터페이스처럼 하나의 메소드만이 선언되어 람다식을 다루기 위해
정의된 인터페이스를 함수형 인터페이스라고 부른다.

@FunctionalInterface
interface MyFunction { // 함수형 인터페이스 MyFunction 정의
	public abstract int max(int a, int b);
}

단, 함수형 인터페이스를 정의하기 위해서는 조건이 있다.

  • 오직 하나의 추상 메소드만이 정의되어 있어야 한다!

람다식과 인터페이스의 메소드가 1대1로 연결되어야 하기 때문에 하나의 메소드만 정의되어 있어야한다.
주의할 점은 static 메소드와 default 메소드는 개수에 포함되지 않는다.

@FunctionalInterface 어노테이션은 컴파일러가 함수형 인터페이스를 올바르게 정의했는지 확인해주는 기능이므로, 되도록이면 붙이자!

함수형 인터페이스 예제

기존에는 인터페이스의 메소드 하나를 구현하는데에도 복잡했다.

	List<String> list = Arrays.sort("aaa","bbb","abc","cca","aca");
    
    Collections.sort(list, new Comparator<String>() {
    	public int compare(String s1, String s2) {
        	return s2.compareTo(s1);
        }
    }

함수형 인터페이스 Comparatorcompare 메소드를 저렇게 구현했어야 했다.

그러나 람다식을 사용하면 더 간단히 처리할 수 있게 되었다.

	Collections.sort(list, (s1, s2) -> s2.compareTo(s1));
profile
자바 스프링 공부하는 정리 블로그!

0개의 댓글