우주코딩
람다 문법 본문
메서드 레퍼런스 - 스태틱 메서드 레퍼런스
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();
'자바 본 강의' 카테고리의 다른 글
List와 Set, HashSet, HashMap (0) | 2021.08.26 |
---|---|
인터페이스 정리, Stack 클래스, Stack과 Deque (0) | 2021.08.26 |
자바 API : ArrayList에 대해 (0) | 2021.08.23 |
제네릭, 제네릭 레퍼런스, 제네릭 파라미터 (0) | 2021.08.23 |
익명 클래스, 익명 클래스의 생성자 호출 (0) | 2021.08.17 |