코드 그라데이션

후발대 16일차 설명 추가 코드 본문

Java/후발대

후발대 16일차 설명 추가 코드

완벽한 장면 2023. 2. 12. 11:07

람다식

_03_Lambda

//Day16
public class _03_Lamda {

  public static void main(String[] args) {
    //람다식 : 간결한 형태의 코드 뭉치
    // (전달값 1, 전달값 2 -> { 코드 }
  }

  // <1> 기본 형태 : 뭔가를 출력하는 함수
  /*
  public void print() {
    String s = "test";
    System.out.println(s);
  }
   */

  // 이걸 람다식으로 바꾸는 연습
  // 1. 람다식은 public과 메서드 명이 필요가 없다(지움)
  // 2. 람다식에서는 무언가 리턴 타입이 필요한 부분이 있다면 자동으로 지정해주므로 void 삭제
  // 3. 전달값과 메서드 바디 사이에 화살표로 연결 필요
  // 지금까지 하면 print 메서드를 람다식으로 바꾸는 것 완성
  // 그런데 빨간 줄이 나타나는 이유는 이게 지금 바로 람다를 사용할 수 없기 때문(지금은 형태만 본다.
    /*
  위 식과 비교해보면
  접근제어자, 반환타입, 메서드명은 사라지고
  파라미터 받는 부분과 메서드 바디는 남아있고, 화살표가 생긴 모습을 확인할 수 있다.
     */
   /*
     () -> {
    String s = "test";
    System.out.println(s);
  }
   */

  //<2> 문자열 하나를 전달값으로 받는 메서드를 람다식으로 만들기.
  /*
  public void print(String s) {
    System.out.println(s);
  }
   */
  // 일단 위의 형태처럼 1, 2, 3은 똑같다.
  // 4. 그리고 메서드 바디가 한 줄만 있으면 위로 올리고(중괄호 옆으로)
  // 5. 중괄호를 지울 수 있다.
  // 6. 또한 바디 끝나는 시점의 ; 도 지운다.
  // 7. 전달되는 자료형이 String이라는 건 컴파일러가 미리 알고 있다. 그러므로 지운다.
  // 8. 그리고 전달값이 한 개다, 그럼 그걸 감싸고 있는 괄호도 지워도 된다.
  /*
   s -> System.out.println(s)
  */

  //<3> 전달값이 두 개, 반환값이 있는 메서드 람다식 변환하기
  /*
  public int add(int x, int y) {
     return x+y;
   }
   */

  // 맨 처음처럼 1, 2 삭제
  // 3. 소괄호와 중괄호 -> 로 연결
  // 4. 파라미터 안의 자료형도 컴파일러가 알 수 있기 때문에 int 삭제
  // 5. 한 줄로 되게 줄을 올림
  //** return이 포함된 경우는 중괄호 삭제 불가능하다!
  // 6. 만약 리턴을 제외해버린다면, 중괄호 삭제 가능, 세미콜론 삭제 가능
 /*
  (x, y) -> x + y;
  */

}

 

_04_FunctionalInterFace

public class _04_FunctionalInterFace {
// 달러 금액을 입력하면, 우리 돈으로 얼마인지를 알려주는(변환해주는) 프로그램 만들기

  public static void main(String[] args) {
    // KRWConverter 객체 만들어서 실행해보기
    KRWConverter16 converter = new KRWConverter16();

    // 1. 전달값이 하나도 없는 경우
    ConvertibleWithNoParams c1 = () -> System.out.println("1 달러 = 1200 원");
    c1.convert();

    // 2. 두 줄 이상 코드가 있는 경우
    // 그냥 새로운 인터페이스 안 만들고 c1 끌어다가 쓰심.
    c1 = () -> {
      int USD = 5;
      int KRW = 1200;
      System.out.println(USD + " 달러 = " + (USD * KRW) + " 원");
    };
    c1.convert(); //5 달러 = 6000 원 출력

    // 3. 전달값이 2개인 경우
    ConvertibleWithTwoParams c2 = (USD, KRW) -> System.out.println(USD + " 달러 = " + (USD * KRW) + " 원");
    c2.convert(10, 1200);

    // 4. 반환값이 있는 경우
    ConvertibleWithReturn c3 = (USD, KRW) ->  USD * KRW;
    //c3.convert(20, 1200);
    // 그런데 이건 원래 반환값이 있는 거였잖아. 여기서 convert에 대고 ctrl + alt + v 하면 리턴 타입형 자동 삽입됨.
    int result = c3.convert(20, 1200); // 헷갈릴 수 있어서 저장 변수명 result로 변경했음.
    // 확인하기 위해서
    System.out.println("20 달러 = " + result + " 원");

    //----------------------- 앞 내용은 뒤로 미뤄두고, 다른 것 실습!
    //converter.convert(1); // 1 달러 = 1200 원 출력

    // convertUSD(converter, 2); // 2 달러 = 2400 원 출력.

    /*
    convertUSD(public void convert ( int USD){
      System.out.println(USD + " 달러 = " + (USD * 1200) + " 원");
    } ,2);
  }
  요 난잡한 모양에서, 람다식 이용해서 정리.
     */
    /*
    람다식 이용한 정리법(복잡하지만 한 번 더 써볼게.)
    1. 접근제어자 2. 함수명 3. 반환형 지우기
    4. 전달값 자료명 int 삭제 5. 전달값과 바디 사이에 -> 삽입
    5. 한 줄로 올린다. 그러면 한 줄일 때는 중괄호 삭제
    6. 세미콜론 삭제
     */
   // convertUSD((USD) -> System.out.println(USD + " 달러 = " + (USD * 1200) + " 원") ,1);
  } // 실행하면 2 달러 = 2400 원 출력됨.

  /*
  // 이제 제가(튜터님)요. (USD) -> System.out.println(USD + " 달러 = " + (USD * 1200) + " 원")만 따로 떼서
  // 인터페이스의 객체로 만드는 일을 해보려고 합니다.
  Convertible16 convertible = (USD) -> System.out.println(USD + " 달러 = " + (USD * 1200) + " 원");
  convertUSD(convertible, 2); // 함수형 인터페이스

  보통의 프로그래밍 언어에서는
  메서드는 클래스 내부에서 어떤 일(기능)을 하는 것, 함수는 클래스 밖에서 어떤 정의한 것인데,
  자바는 객체지향 언어라서 모든 기능을 클래스 내에서만 정의할 수 있기 때문에 메서드라고 부르는 것 뿐

  함수형 인터페이스를 사용하려면,
  "인터페이스에는 오직 딱 하나의 추상 메서드가 존재해야 한다"는 조건이 있어야 한다.
  함수의 동작이 인터페이스의 추상 메서드 동작과 일대일 매핑이 되기 때문에,
  두 개 이상이 있으면 안 된다는 것

  개발자의 실수를 방지하기 위해서 코딩 시점에 @FunctionalInterface 어노테이션을 붙여준다.

   */


    /*
    첫 번째와 똑같은 결과가 나왔는데, 왜 그럴까?
    => 너무 당연하다. 우리는 converter.convert(1);에서 하는 동작을 아래의 convertUSD() 메서드로 옮긴 것일 뿐이다.

    그런데 코드를 잘 뜯어보면,
    convertUSD() 메소드를 호출하면, converter를 전달을 하는데, 아래에 있는 메서드 내에서 동작은,
    converter 내의 convert 메서드를 호출하는 것일 뿐.
    그래서 이 동작하는 convert(2) 부분은,
    우리가 Convertible16 인터페이스를 통해 구현한 KWRConverter의 convert(1) 메서드를 호출하는 것과 똑같다.
    (괄호안은 헷갈리지 말라고 위해 일부러 전달값을 넣어놓은 것임)

    <추가>
    자 그래서요. convertUSD(converter, 2); 에서 converter 부분을 삭제를 하고,
    지금 converter 부분은 KRWConverter 클래스에 있는 메서드와 완전히 동일한 기능을 수행하고 있으니 가져와서 붙여넣어 볼게요.
    그리고 람다식 이용해서 코드를 단순화시켜 보죠.
     */

     /*
     <또 추가 2>
     자 그런데, 지금 우리가 하고 있는 것이 무엇이냐면, convertUSD() 를 호출하는 것은 똑같다.
     여기서 우리는 전달값을 두 개를 주고 있지. 하나는 converter, 다른 하나는 USD
     지금 convertUSD((USD) -> System.out.println(USD + " 달러 = " + (USD * 1200) + " 원") ,2);을 다시 보면
     USD는 정의가 되어 있다(값: 2). 그러면 converter는?
     (USD) -> System.out.println(USD + " 달러 = " + (USD * 1200) + " 원") 이 긴~ 걸로 대체되었음을 알 수 있음.
     즉, 아래 메서드 내려가서 비교해보면 Convertible16 인터페이스가 이 람다식으로 구현이 되어 있는 꼴
     이 코드는 인터페이스의 어떤 코드와 완벽하게 매칭된다는 뜻이지.
     따라서 우리는 지금 메서드를 변수처럼 쓰면서 호출하고 있다고 볼 수 있는 것이다.
      */



  // 아래에 메서드 분리해서 converter.convert()가 하는 내용을 출력해보자

  // 우리가 지금 환율을 변환하는 메서드를 만드는 것이므로,
  // 괄호 안에 인터페이스를 넣어주고(KRWConverter을 사용할 수도 있지만 다형성에 의해서 가능),
  // 얼마의 달러를 어떻게 변환해줄거냐를 계산 시켜야 하므로 int로 USD 달러를 받는다.
  public static void convertUSD(Convertible16 converter, int USD) { //원래는 convertiber16이어야 하지만 편의상  converter라고 썼음
   converter.convert(USD);

  }

}

 

KRWConverter

// USD 돈으로 우리 돈으로 얼마인지를 알려주는(변환해주는) 것을 구현해주는 클래스임
public class KRWConverter16 implements Convertible16 {

  // 환율은 1,200원이라고 가정하자.
  @Override
  public void convert(int USD) {
    System.out.println(USD + " 달러 = " + (USD*1200) + " 원");
    // 실행하면 "1 달러 = 1200 원" 이렇게 나올 듯.
    // 이 클래스를 객체로 만들어서 한 번 실행해보겠다. Class _04_로 간다.
  }
}

 

Convertible

@FunctionalInterface
public interface Convertible16 {
  void convert(int USD); // 인터페이스니까 본문 없지. 구현하는 클래스는 KRWConverter

}

 

ConvertibleWithNoParams

@FunctionalInterface
public interface ConvertibleWithNoParams {
  void convert();

}

 

ConvertibleWithTwoParams

@FunctionalInterface
public interface ConvertibleWithTwoParams {
  void convert(int USD, int KRW);
}

 

ConvertibleWithReturn

@FunctionalInterface
public interface ConvertibleWithReturn {
  int convert(int USD, int KRW);

}

 

마지막 추가 설명

자바는 객체 지향으로 되어 있어서 클래스 안에 메서드가 들어있는 형식으로 코드를 작성한다.
따라서 다른 프로그래밍 언어와는 다르게 함수를 따로 가져다 쓰는 것이 없다.
자바는 하나의 추상메서드를 가진 함수형 인터페이스를 만듦으로써 다양한 기능에 대응하는 람다식을 통해
함수를 사용할 수 있게 된다.
이렇게 되면 함수를 호출하는 방식을 사용할 수 있게 된다.

"자바는 객체를 1급 시민으로 갖는다"
1) 변수에 담을 수 있다.
2) 인자로 전달할 수 있다.
3) 반환값으로 전달할 수 있다.
이 세 가지 조건을 충족하는 것이 1급 시민!

함수형 프로그래밍이 대두되면서, 함수를 객체로 담을 수 없는 자바는
이를 가능케 하고자 함수형 인터페이스를 가지고 람다식을 도입해 1급 시민처럼 사용할 수 있게 되었다!

 

728x90

'Java > 후발대' 카테고리의 다른 글

후발대 17일차 전체 코드  (0) 2023.02.19
첫 번째 과제 개념정리  (0) 2023.02.13
후발대 16일차 전체 코드  (0) 2023.02.12
후발대 15일차 설명 추가 코드  (0) 2023.02.11
후발대 15일차 전체 코드  (0) 2023.02.11
Comments