본문 바로가기
JAVA

Java8 람다

by FraisGout 2020. 7. 4.

람다 표현식(lambda expression)이란?

람다 표현식(lambda expression)이란 간단히 말해 메소드를 하나의 식으로 표현한 것입니다.

 

메소드

int min(int x, int y) {

 

return x < y ? x : y;

 

}

 

람다 표현식

(x, y) -> x < y ? x : y;

 

 

 

위의 예제처럼 메소드를 람다 표현식으로 표현하면, 클래스를 작성하고 객체를 생성하지 않아도 메소드를 사용할 수 있습니다.

 

 

 

그런데 자바에서는 클래스의 선언과 동시에 객체를 생성하므로, 단 하나의 객체만을 생성할 수 있는 클래스를 익명 클래스라고 합니다.

 

따라서 자바에서 람다 표현식은 익명 클래스와 같다고 할 수 있습니다.

 

람다 표현식

(x, y) -> x < y ? x : y;

 

익명 클래스

new Object() {

 

int min(int x, int y) {

 

return x < y ? x : y;

 

}

 

}

 

 

 

이러한 람다 표현식은 메소드의 매개변수로 전달될 수도 있으며, 메소드의 결괏값으로 반환될 수도 있습니다.

 

따라서 람다 표현식을 사용하면, 기존의 불필요한 코드를 줄여주고, 작성된 코드의 가독성을 높여줍니다.

 

Java SE 8부터는 이러한 람다 표현식을 사용하여 자바에서도 함수형 프로그래밍을 할 수 있게 되었습니다.

 

람다 표현식 작성

자바에서는 화살표(->) 기호를 사용하여 람다 표현식을 작성할 수 있습니다.

 

문법

(매개변수목록) -> { 함수몸체 }

 

 

 

자바에서 람다 표현식을 작성할 때 유의해야 할 사항은 다음과 같습니다.

 

 

 

1. 매개변수의 타입을 추론할 수 있는 경우에는 타입을 생략할 수 있습니다.

 

2. 매개변수가 하나인 경우에는 괄호(())를 생략할 수 있습니다.

 

3. 함수의 몸체가 하나의 명령문만으로 이루어진 경우에는 중괄호({})를 생략할 수 있습니다. (이때 세미콜론(;)은 붙이지 않음)

 

4. 함수의 몸체가 하나의 return 문으로만 이루어진 경우에는 중괄호({})를 생략할 수 없습니다.

 

5. return 문 대신 표현식을 사용할 수 있으며, 이때 반환값은 표현식의 결괏값이 됩니다. (이때 세미콜론(;)은 붙이지 않음)

 

 

 

다음 예제는 전통적인 방식의 스레드 생성과 람다 표현식을 사용한 스레드 생성을 비교하는 예제입니다.

 

예제

new Thread(new Runnable() {

 

public void run() {

 

System.out.println("전통적인 방식의 일회용 스레드 생성");

 

}

 

}).start();

 

 

 

new Thread(()->{

 

System.out.println("람다 표현식을 사용한 일회용 스레드 생성");

 

}).start();

 

위의 예제에서 볼 수 있듯이 람다 표현식을 사용하면 불필요한 코드를 줄일 수 있으며, 코드의 가독성이 훨씬 좋아집니다.

 

함수형 인터페이스(functional interface)

람다 표현식을 사용할 때는 람다 표현식을 저장하기 위한 참조 변수의 타입을 결정해야만 합니다.

 

문법

참조변수의타입 참조변수의이름 = 람다 표현식

 

 

 

위의 문법처럼 람다 표현식을 하나의 변수에 대입할 때 사용하는 참조 변수의 타입을 함수형 인터페이스라고 부릅니다.

 

 

 

함수형 인터페이스는 추상 클래스와는 달리 단 하나의 추상 메소드만을 가져야 합니다.

 

또한, 다음과 같은 어노테이션(annotation)을 사용하여 함수형 인터페이스임을 명시할 수 있습니다.

 

문법

@FunctionalInterface

 

 

 

위와 같은 어노테이션을 인터페이스의 선언 앞에 붙이면, 컴파일러는 해당 인터페이스를 함수형 인터페이스로 인식합니다.

 

자바 컴파일러는 이렇게 명시된 함수형 인터페이스에 두 개 이상의 메소드가 선언되면 오류를 발생시킵니다.

 

 

 

다음 예제는 함수형 인터페이스를 선언하고 사용하는 예제입니다.

 

예제

@FunctionalInterface

 

interface Calc { // 함수형 인터페이스의 선언

 

public int min(int x, int y);

 

}

 

 

 

public class Lambda02 {

 

public static void main(String[] args){

 

Calc minNum = (x, y) -> x < y ? x : y; // 추상 메소드의 구현

 

System.out.println(minNum.min(3, 4)); // 함수형 인터페이스의 사용

 

}

 

}

 

자바는 java.util.function 패키지를 통해 여러 상황에서 사용할 수 있는 다양한 함수형 인터페이스를 미리 정의하여 제공합니다.

 

 

메소드 참조(method reference)

메소드 참조(method reference)는 람다 표현식이 단 하나의 메소드만을 호출하는 경우에 해당 람다 표현식에서 불필요한 매개변수를 제거하고 사용할 수 있도록 해줍니다.

 

 

 

메소드 참조를 사용하면 불필요한 매개변수를 제거하고 다음과 같이 '::' 기호를 사용하여 표현할 수 있습니다.

 

문법

클래스이름::메소드이름

 

또는

 

참조변수이름::메소드이름

 

 

 

다음 예제는 두 개의 값을 전달받아 제곱 연산을 수행하는 Math 클래스의 클래스 메소드인 pow() 메소드를 호출하는 람다 표현식입니다.

 

예제

(base, exponent) -> Math.pow(base, exponent);

 

 

 

위의 예제는 단순히 Math 클래스의 pow() 메소드로 인수를 전달하는 역할만 하므로, 메소드 참조를 사용하여 다음과 같이 간단히 표현할 수 있습니다.

 

예제

Math::pow;

 

 

 

또한, 특정 인스턴스의 메소드를 참조할 때에도 참조 변수의 이름을 통해 메소드 참조를 사용할 수 있습니다.

 

예제

MyClass obj = new MyClass;

 

Function<String, Boolean> func = (a) -> obj.equals(a); // 람다 표현식

 

Function<String, Boolean> func = obj::equals(a); // 메소드 참조

 

 

 

다음 예제는 람다 표현식과 메소드 참조를 비교하는 예제입니다.

 

예제

DoubleUnaryOperator oper;

 

 

 

oper = (n) -> Math.abs(n); // 람다 표현식

 

System.out.println(oper.applyAsDouble(-5));

 

 

 

oper = Math::abs; // 메소드 참조

 

System.out.println(oper.applyAsDouble(-5));

 

 

DoubleUnaryOperator 인터페이스는 한 개의 double 형 매개변수를 전달받아 한 개의 double 형 값을 반환하는 java.util.function 패키지에서 제공하는 함수형 인터페이스입니다.

생성자 참조

생성자를 호출하는 람다 표현식도 앞서 살펴본 메소드 참조를 이용할 수 있습니다.

 

, 단순히 객체를 생성하고 반환하는 람다 표현식은 생성자 참조로 변환할 수 있습니다.

 

 

 

다음 예제는 단순히 객체를 생성하고 반환하는 람다 표현식입니다.

 

예제

(a) -> { return new Object(a); }

 

 

 

위의 예제는 단순히 Object 클래스의 인스턴스를 생성하고 반환하기만 하므로, 생성자 참조를 사용하여 다음과 같이 간단히 표현할 수 있습니다.

 

예제

Object::new;

 

 

 

이때 해당 생성자가 존재하지 않으면 컴파일 시 오류가 발생합니다.

 

 

 

또한, 배열을 생성할 때에도 다음과 같이 생성자 참조를 사용할 수 있습니다.

 

예제

Function<Integer, double[]> func1 = a -> new double[a]; // 람다 표현식

 

Function<Integer, double[]> func2 = double[]::new; // 생성자 참조

'JAVA' 카테고리의 다른 글

Java8 time  (0) 2020.07.04
Java8 스트림  (0) 2020.07.04
Java 스레드  (0) 2020.07.04
Java 입력/출력  (0) 2020.07.04
Java 예외처리  (0) 2020.07.04

댓글