본문 바로가기

Language/Java

[JAVA] 람다식과 함수형 인터페이스

1. 람다식

(1) 정의

익명함수 (이름이 없는 함수) == 접근제어자, 반환형, 함수이름, 파라미터의 자료형 다 필요 없음. 

람다식도 일급 객체이다. 

**일급 객체란? 

데이터나 변수를 받을 수 있는 객체, 어떤 매소드의 파라미터로 들어갈 수 있는 객체, 어떤 매소드의 반환 값이 될 수 있는 객체 이다.

(2) 형태

(전달값 1, 전달값2, ...) -> { 실행코드  }

 

2. 함수형 인터페이스

(1) 뜻 

추상 매소드가 오직 하나 뿐인 인터페이스 

(2)람다식과의 관계

람다식은 오직 함수형 인터페이스로만 접근 가능.

 

** why?  

인터페이스에 추상 매소드가 두 개이면, 람다식과 매칭되는 추상 매소드가 무엇인지 모호해진다. 

따라서 추상 매소드가 오직 하나인 함수형 인터페이스만이 람다식과 매칭이 가능하여 쓸 수 있다. 

 

 

(둘 사이의 파라미터 갯수, 리턴값 유무는 맞춰야 한다.)

3. 코드 리뷰

(1) 추상 매소드에 인수 1개, 반환형 void 인 경우

// <<인터페이스 부분>>
//함수형 인터페이스에 추상 매소드가 1 개여야만 한다고 컴퓨터에게 가르쳐 주기 위해 어노테이션 이용
// 해당 어노테이션 있으면, 추상 매소드가 2개가 될 때, 컴퓨터가 에러를 말해준다.

@FunctionalInterface
public interface Convertible {

    // USD를 환전하는 추상 매소드
    void convert(int USD);
}
 
 /* 함수형 인터페이스 객체와 그 객체의 매소드에 넣을 값으로 이루어진 함수
 
 	인터페이스는 일반적으로 객체를 가질 수 없지만, 람다식으로 추상매소드를 바로 구체화 시키기 때문에
    람다식으로 매칭한 경우에는 가능 */
    
 public static void convertUSD(Convertible converter, int USD){
        converter.convert(USD);
    }
}
// 람다식을 통해 인터페이스에서 바로 객체를 생성했고, 
//(다형성의 원리: 부모 클래스의 참조 변수는 자식 클래스의 객체를 참조할 수 있다.)
Convertible convertible = (USD) -> System.out.println(USD + "달러 = "+ (USD *1400) + " 원");

// 만들어진 객체와 해당 객체 매소드에 넣을 값을 파라미터로 보냈다. 
// 람다식이 곧 추상 매소드의 구체화 이므로 해당 2는 USD로 보내진다.
convertUSD(convertible,2);
// * 객체 생성 과정 없이 람다식 자체를 파라미터로 보낼 수도 있다. 
// * 어짜피 파라미터인 Convertible converter와 만나 객체가 생성되므로 밑과 같은 표기도 가능하다. 

convertUSD((USD) -> System.out.println(USD + "달러 = "+ (USD *1400) + " 원"), 1);

(2) 추상 매소드에 인수 없고, 반환형도 void인 경우

// 함수형 인터페이스

@FunctionalInterface
public interface ConvertibleWithNoParams {
    void convert();
}
ConvertibleWithNoParams c1 = () -> System.out.println("1달러는 1400원");

// 추상 매소드 호출하면 위의 람다식이 해당 호출에 응하여 일을 수행한다.
c1.convert();

(3) 람다식의 코드 부분이 한 줄인 경우와 두 줄 이상인 경우 구분

** 람다식의 코드 부분이 두 줄 이상인 경우 () -> {};에서 {}; 부분을 꼭 써줘야 한다. (한 줄인 경우 생략 가능)

// 위의 함수형 인터페이스 계속 사용 
c1 = () -> {
    int USD = 5;
    int KRW = 1400;
    System.out.println(USD + "달러 = "+ (USD *KRW) + " 원");
};

(3) 추상 매소드에 인수가 2개 이상인 경우 반환형은 void

** 둘이 인수 갯수 맞춰주면 됨.

public interface ConvertibleWithTwoParams {
    void convert(int USD, int KRW);
}
ConvertibleWithTwoParams c2 = (USD, KRW) -> System.out.println(USD + "달러 = "+ (USD *KRW) + " 원");
c2.convert(10,1400);

(4) 추상 매소드에 반환 값이 있는 경우

** return이 있는 경우에도 {};을 꼭 써줘야 한다. 

** 추상 매소드가 반환형 갖는다고 해서 람다식에 꼭 return = ~~;를 써줄 필요는 없다.  

    밑의 경우처럼 그냥 return 빼고 적어도 람다식이 알아서 return 옆에 꽂아 넣는다. 

 

// int 반환값이 필요한 인터페이스
@FunctionalInterface
public interface ConvertibleWithReturn {
    int convert(int USD, int KRW);
}
//원래 return을 써서 나타내면 {return USD*KRW;}; 로 해야하지만, return을 안 쓰니 {};을 쓸 의무도 사라졌다.

ConvertibleWithReturn c3 = (USD, KRW) -> USD * KRW;
int result = c3.convert(20, 1400);
System.out.println("20 달러 = "+result+" 원");

4. 스스로 해보기 

    /*  추상 매소드 인수 1개, 반환형 void 인 경우(함수 경유 나타내기, 그냥 나타내기)
    *   추상 매소드가 인수도 없고 반환형도 void 인 경우
    *   추상 매소드가 인수 2개에  반환형도 있는 경우  */

import WorkOut_Myself.Translator.TranslateEngTo;
import WorkOut_Myself.Translator.TranslateHitoKR;
import WorkOut_Myself.Translator.TranslateTwo;

public class FunctionalInterface_myself {
    public static void main(String[] args) {
        TranslateEngTo Hello = (hello) -> System.out.println(hello +"은(는) 한국어로 \"안녕하세요\" 입니다.");
        EngToKR(Hello,"Hi");

        EngToKR((Hi) -> System.out.println(Hi +"은(는) 한국어로 \"안녕하세요\" 입니다."),"하지메마시테" );

        TranslateHitoKR AnyLanguage = () -> System.out.println("Hello는 한국어로 \"안녕하세요.\" 입니다.");
        AnyLanguage.Translate();

        TranslateTwo Korean = (ENG, JPN) -> {
          return   "영어인 " + ENG + "은(는) 한국어로 안녕하세요 입니다. 그리고 일본어인 " + JPN + "은(는) 한국어로 안녕하세요 입니다.";
        };
       String s = Korean.Translate("Hello!", "곤니치와");
        System.out.println(s);
    }

    public static void EngToKR (TranslateEngTo TL, String s){
        TL.Translate(s);
    }
}

'Language > Java' 카테고리의 다른 글

[JAVA] Stream 실습  (0) 2023.02.19
[JAVA] Stream  (0) 2023.02.18
[JAVA] 익명 클래스  (0) 2023.02.15
[JAVA] Iterator  (0) 2023.02.15
[JAVA] HashMap  (0) 2023.02.13