개발소설

[JAVA] 람다 (Lambda) 본문

자바

[JAVA] 람다 (Lambda)

ChaeHing 2023. 3. 8. 17:00

람다 (Lambda)

  • 함수형 프로그램 기법을 지원하는 자바의 문법 요소
  • 매서드를 하나의 식으로 표현한 것
  • 코드를 매우 간결하고 명확하게 표현가능한 장점이 있다.

 

람다식의 기본 문법

  • 기본적으로 반환타입, 이름을 생략 -> 익명  함수(anonymous function)
// 기존 메서드
int sum(int num1, int num2){
   return num1+num2;
}

// 기본 람다식, 반환타입 메서드 이름 생략, (화살표) -> 추가
(int num1, int num2) -> { return num1+num2 };

// 기존
void print(){
System.out.println("Hello");
}

// 람다식
() -> System.out.println("Hello");

특정 조건 충족시 람다식을 더욱 축약

  1. 메서드 바디에 실행문 하나만 존재할 경우 중괄호 ({}), return문, 세미콜론(;) 생략
  2. 매개변수 타입을 함수형 인터페이스를 통해 유추 할수 있는경우 매개변수 타입 생략
//기본 람다식
(int num1, int num2) -> { return num1+num2 };

// 메서드블록에 실행문이 하나 일 경우
(int num1, int num2) -> num1 + num2

// 함수형 인터페이스로 매개변수의 타입을 유추 할 수 있을때
(num1, num2) -> num1 + num2

함수형 인터페이스

  • 자바에서 함수는 반드시 클래스 안에 정의 되어야하고, 객체로 생성 한뒤 호출 해야한다.
  • 람다식도 객체, 이름이 없기 때문에 익명 객체라 할 수 있다.
(num1, num2) -> num1 + num2

// 람다식의 객체 표현
new Object(){
	int sum(int num1, int num2){
    	return num1+num2;
    	}
}

obj.sum(1,2) // error 발생

//
java: cannot find symbol
  symbol:   method sum(int,int)
  location: variable obj of type java.lang.Object
  • 익명 객체는 익명 클래스를 통해 만들 수 있다.
  • 익명 클래스란 객체의 선언과 생성을 동시에 하여 오직 하나의 객체를 생성, 단 한번만 사용되는 일회용 클래스
  • 람다식도 객체기 때문에 객체를 사용하려면 객체에 접근하기 위한 참조 변수가 필요
  • 하지만 Object클래스 에는 sum이라는 메서드가 없기 때문에 Object 타입의 참조변수를 사용하면 메서드를 사용 불가
  • 이러한 문제를 해결 하기 위해 함수형 인터페이스(Functional Interface)를 사용

 

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

  • 기존의 인터페이스의 문법을 활용하여 람다식을 다룬다.
  • 함수형 인터페이스에는 단하나의 추상 메서드만 선언
    • 람다식과 인터페이스의 메서드의 1:1 매칭을 위해
// 함수형 인터페이스 생성
@FunctionalInterface // 애너테이션, 컴파일러가 인터페이스가 바르게 정의 되었는지 확인
interface FunctionInterface {
    int sum(int num1, int num2); // 추상메서드, 하나만 있어야한다.
}


// 함수형 인터페이스를 참조 변수로 생성
FunctionInterface functionInterface = (num1, num2) -> num1 + num2;
System.out.println(functionInterface.sum(5, 10)); // sum() 호출

각 유형의 람다식

// 매개변수와 리턴값이 없는 람다식
@FunctionalInterface
public interface InterfaceEx {
    void accept();
}

InterfaceEx interfaceEx = () -> System.out.println("accept() 호출");
interfaceEx.accept();  // accept() 호출


// 매개변수가 있는 람다식
@FunctionalInterface
public interface InterfaceEx {
    void accept(int num);
}

InterfaceEx interfaceEx = (num) -> {
	int sum = num + 5;
	System.out.println(num);
}

interfaceEx.accept(30); // 35 


// 리턴값 있는 람다식
@FunctionalInterface
public interface InterfaceEx {
    int accept(int num1, int num2); 
}

InterfaceEx interfaceEx = (num1, num2) -> num1 + num2;
int result = interfaceEx.accept(5, 5); // 리턴값을 변수에 저장
System.out.println(result); // 10

interfaceEx = (num1, num2) -> num1 * num2;
result = interfaceEx.accept(5, 5);
System.out.println(result); // 25

기본적인 함수형 인터페이스

 

java.util.function (Java Platform SE 8 )

Interface Summary  Interface Description BiConsumer Represents an operation that accepts two input arguments and returns no result. BiFunction Represents a function that accepts two arguments and produces a result. BinaryOperator Represents an operation u

docs.oracle.com

메서드 레퍼런스 (메서드 참조)

  • 불필요한 매개 변수를 제거 할때 사용
  • 더욱더 간단하게 사용가능 
  • 매개변수(입력값)과 반환타입(출력값)이 유추가 될경우
// 정적 메서드 참조
클래스 :: 메서드

// 인스턴스 메서드 참조
참조 변수 :: 메서드
public class Calculator {
    public static int staticMethod(int x, int y) {
        return x + y;
    }

    public int instanceMethod(int x, int y) {
        return x * y;
    }
}

import java.util.function.IntBinaryOperator;

IntBinaryOperator operator; // int형 매개값 두개를 입력받아 int값을 리턴
                            // 기본 함수형 인터페이스

operator = Calculator::staticMethod; // 정적 메서드
System.out.println("정적메서드: " + operator.applyAsInt(5, 10));

Calculator calculator = new Calculator(); // Calculator 인스턴스화
operator = calculator::instanceMethod; // 인스턴스 메서드
System.out.println("인스턴스 메서드: "+ operator.applyAsInt(5, 10));


/*
정적메서드: 15
인스턴스 메서드: 50
*/

생성자 참조

  • 생성자를 참조하는것은 객체 생성을 의미
  • 객체를 생성하고 리턴하도록 구성된 람다식은 생성자 참조로 대치 가능
  • 생성자 오버로딩으로 여러개 일 경우 함수형 인터페이스의 추상 메서드와 동일한 매개 변수 타입과 개수를 가지고 있는 생성자를 찾는다.
(a,b) -> new 클래스(a,b)

// 생성자 참조 문법
클래스 :: new
public class Player {
    private String name;
    private String team;

    public Player() {
    }

    public Player(String name) {
        System.out.println("Lambda.Player(String name) 실행");
        this.name = name;
    }

    public Player(String name, String team) {
        System.out.println("Lambda.Player(String name, String team) 실행");
        this.name = name;
        this.team = team;
    }

    public String getName() {
        return name;
    }

    public String getNumber() {
        return team;
    }
}
import java.util.function.BiFunction;
import java.util.function.Function;

Function<String, Player> function1 = Player::new; // 기본 함수형 인터페이스,
                                                  //Function<입력타입, 출력타입>
Player player1 = function1.apply("Messi");

BiFunction<String, String, Player> function2 = Player::new; // 기본 함수형 인터페이스 
                                                            //BiFunction<입력타입1, 입력타입2, 출력타입>
Player player = function2.apply("Messi", "PSG");

/*
Player(String name) 실행
Player(String name, String team) 실행
*/

 

'자바' 카테고리의 다른 글

[JAVA] 스트림(Stream)  (0) 2023.03.10
[JAVA] 파일 입출력(I/O)  (0) 2023.03.09
[JAVA] 애너테이션 (Annotation)  (0) 2023.03.08
[JAVA] 컬렉션 프레임 워크 (Collection Framework)  (0) 2023.03.08
[JAVA] 예외 처리(Exception Handling)  (0) 2023.03.07
Comments