Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

우주코딩

람다 문법 본문

자바 본 강의

람다 문법

우주코딩 2021. 8. 25. 09:11

메서드 레퍼런스 - 스태틱 메서드 레퍼런스

static class MyCalculator {
    public static int plus(int a, int b) {return a + b;}
    public static int minus(int a, int b) {return a - b;}
    public static int multiple(int a, int b) {return a * b;}
    public static int divide(int a, int b) {return a / b;}
  }

interface Calculator {
    int compute(int x, int y);
  }


Calculator c1 = MyCalculator::plus;
Calculator c2 = MyCalculator::minus;
Calculator c3 = MyCalculator::multiple;
Calculator c4 = MyCalculator::divide;

c1.compute(200,17); // plus()
c2.compute(200,17); // minus()

메서드 한 개짜리 인터페이스의 구현체를 만들 때

1) 익명 클래스 활용
Calculator obj1 = new Calculator() {
@Override
public int compute(int x, int y) {
return x * y;
}
};

2) 람다 문법 활용
Calculator obj2 = ( x, y) -> x * y;

3) 기존에 작성한 클래스의 스태틱 메서드 중에서 인터페이스의 메서드 규격과 일치하는 메서드가 있다면, 그 메서드를 람다 구현체로 사용할 수 있다.
단 인터페이스에 선언된 메서드의 규격과 일치해야 한다.
새로 코드를 작성할 필요가 없어 편리하다.
규격? 파라미터 타입 및 개수, 리턴 타입
=> 문법:
클래스명::메서드명

=> 메서드 레퍼런스를 지정할 때 리턴 타입의 규칙:

1) 같은 리턴 타입
2) 암시적 형변환 가능한 타입
3) auto-boxing 가능한 타입
4) void
결론,메서드 레퍼런스가 가리키는 실제 메서드를 호출한 후 그 메서드가 리턴한 값이
인터페이스에 정의된 메서드의 리턴 값으로 사용할 수 있다면 문제가 없다.

메서드 레퍼런스를 지정할 때 파라미터 타입 규칙:
=> 인터페이스 규칙에 따라 받은 값을 실제 메서드에 그대로 전달할 수 있다면 가능하다.

그 파라미터 값은 메서드 레퍼런스로 지정된 스태틱 메서드(예: plus())에게 전달될 것이다.
=> 그래서 스태틱 메서드의 파라미터는 항상 인터페이스 메서드에 정의된 파라미터 값을 받을 수 있어야 한다.
스태틱 메서드의 리턴 값은 인터페이스 메서드에 정의된 대로 리턴할 수 있어야 한다.
=> 그래서 스태틱 메서드의 리턴 타입은 인터페이스 메서드의 리턴 타입과 일치하거나 그 타입으로 바꿀 수 있어야 한다.

인스턴스 메서드 레퍼런스

static class Calculator {
    double rate;

    public Calculator(double rate) {
      this.rate = rate;
    }

    public double year(int money) {
      return money * rate / 100;
    }

    public double month(int money) {
      return money * rate / 100 / 12;
    }

    public double day(int money) {
      return money * rate / 100 / 365;
    }
  }

  static interface Interest {
    double compute(int money);
  }

Calculator 보통예금 = new Calculator(0.5);
Calculator 정기예금 = new Calculator(1.5);
Calculator 청년행복예금 = new Calculator(10);

// 인스턴스 레퍼런스 생성

Interest i1 = 보통예금::year;
System.out.printf("년 이자: %.1f\n", i1.compute(10_0000_0000));

Interest i2 = 정기예금::year;
System.out.printf("년 이자: %.1f\n", i2.compute(10_0000_0000));

메서드 한 개짜리 인터페이스의 구현체를 만들 때 기존 인스턴스 메서드를 람다 구현체로 사용할 수 있다.
=> 단 인터페이스에 선언된 메서드의 규격과 일치해야 한다.
=> 보통 특정 인스턴스 값을 가지고 작업해야 할 경우에 이 방식을 사용한다.
=> 규격? 파라미터 타입 및 개수, 리턴 타입
=> 문법:
인스턴스::메서드명


Interest i1 = 보통예금::year;
// 위 코드는 내부적으로 다음과 같다.

public double compute(int money) {
        // 인스턴스 메서드 레퍼런스는 실제
        // 인터페이스 구현체에서 다음과 같이 메서드로 호출된다.
        return 보통예금.year(money);
    }
};

System.out.printf("년 이자: %.1f\n", i1.compute(10_0000_0000));

생성자 레퍼런스

interface ListFactory {
    List create();
  }

  public static void main(String[] args) {

    // 인터페이스에 정의된 메서드가
    // 생성자의 형식과 일치하다면
    // 메서드 레퍼런스로 생성자를 지정할 수 있다.
    //
    // 1) 익명 클래스로 인터페이스 구현
    ListFactory f1 = new ListFactory() {
         public List create() {
           return new ArrayList();
         }
       };

    // 2) 람다 문법으로 인터페이스 구현
    ListFactory f1 = () -> new ArrayList();

    // 3) 메서드 레퍼런스로 인터페이스 구현 
    ListFactory f1 = ArrayList::new;

    // 인터페이스의 메서드를 호출하면
    // 지정된 클래스의 인스턴스를 만든 후 생성자를 호출한다.
    List list = f1.create(); // new ArrayList();

생성자 레퍼런스를 지정하는 것은 다음과 같이 익명 클래스를 만드는 것과 같다.

=> ListFactory f1 = ArrayList::new;

ListFactory f1 = new ListFactory() {
@Override
public List create() {
return new ArrayList();
}
};

List list = f1.create();

Comments