2023_1_21_TIL
객체지향 구조 내에서 람다식 적용 과정
- 함수 -> 기능 또는 동작을 정의
- 메소드 -> 클래스 또는 인터페이스내에 정의된 함수
- 하나의 추상 메소드만 포함하는 인터페이스 -> 함수형 인터페이스
- 함수형 인터페이스의 호출 및 기능을 구현하는 방법을 새롭게 정의한 것 '람다식'
- 람다식을 사용하면 독립적으로 정의한 함수를 호출만 하면 공통기능 사용
- 람다식은 기존의 OPP안에서 함수형 FP를 가능하게 하는 기법
interface A {
void abc();
}
class B implements A {
@Override
public void abc() {System.out.println("메소드 내용 1");}
}
public class RefOfClassConstructor_2 {
public static void main(String[] args) {
A a1 = new B();
a1.abc();
A a2 = new A() {
@Override
public void abc() {System.out.println("메소드 내용 2");}
}
a2.abc();
A a3 = () -> {System.out.println("메소드 내용 3");
a3.abc();
- 람다식은 익명 이너클래스의 축약된 형태
- 하나의 추상 메소드만을 가진 FP만 람다식으로 구현
- 이유는 익명 이너클래스의 축약된 형태이기 때문에(2개이상 이면 어떤 메소드를 구현하는 것인지 구분을 못함)
람다식의 기본 문법 및 약식 표현
- 람다식의 기본 문법
- 람다식의 약식 표현
- {실행문1개} = 실행문1개(2개이상은 X)
- 입력매개변수 자료형은 생략 가능 -> FP에 포함된 추상 메소드의 입력매개변수 타입으로 유추 가능
- (입력매개변수1개) = 입력매개변수1개(소괄호 생략시 매개변수의 자료형 생략)
- return문 1개 return 생략(중괄호도 생략)
구현 메소드의 약식표현
- 람다식의 사용
- 익명 이녀 클래스 내부 구현 매소드의 약식 표현
- 참조의 의미 -> 함수형 인터페이스의 메소드를 구현하는 데 있어 구현대신, 이미 있는 기능을 가져다 사용하겠다는 것
- 메소드 참조
- 즉, 구현 메소드의 약식표현은 함수형 인터페이스의 추상메소드를 직접 구현했을 때, 메소드 참조는 이미 있는 메소드로 대체했을 때인 것.
- 생성자 참조
- 구현 메소드의 내용이 객체 생성 코드만으로 고정되어 있을 때
- 구현 메소드의 약식표현
- 람다식의 활용
- 함수형 인터페이스의 객체 생성과정에서 익명이너 클래스를 이용해서 객체 생성한 것
- 직접 추상 메소드를 구현하는 형태 -> return 타입으로 4가지 존재
interface A {void method1();}
interface B {void method2(int a);}
interface C {int method3();}
interface D {double method4(int a, double b);}
public class FunctionToLambdaExpression {
public static void main(String[] args) {
A a1 = new A() {
@Override
public void method1() {
System.out.println("입력X 리턴X 함수");
}
};
A a2 = () -> {System.out.println("입력X 리턴X 함수");};
A a3 = () -> System.out.println("입력X 리턴X 함수");
B b1 = new B() {
@Override
public void method2(int a) {
System.out.println("입력O 리턴X 함수");
}
};
B b2 = (int a) -> {System.out.println("입력O 리턴X 함수");};
B b3 = (a) -> {System.out.println("입력O 리턴X 함수");};
B b4 = (a) -> System.out.println("입력O 리턴X 함수");
B b5 = a -> System.out.println("입력O 리턴X 함수");
C c1 = new C() {
@Override
public int method3() {
return 4;
}
};
C c2 = () -> {return 4;};
C c3 = () -> 4;
D d1 = new D() {
@Override
public double method4(int a, double b) {
return a + b;
}
};
D d2 = (int a, double b) -> {return a + b;};
D d3 = (a, b) -> {return a + b;};
D d4 = (a, b) -> a + b;
}
}
메소드 참조
- 람다식의 활용
- 추상메소드를 직접 구현 대신, 구현되어있는 것 참조
- 참조 방식 -> 인스턴스 메소드 참조(방법 2가지) | 정적 메소드 참조
- 참조 방식 1. 정의되어 있는 인스턴스 메소드 참조(인스턴스 메소드 참조)
- 이미 정의되어 있는 인스턴스 메소드를 참조하는 것
- 인스턴스 메소드 참조할려면 객체먼저 생성 필요
- 형태 -> 클래스객체 참조변수::인스턴스메소드
interface A {void abc();}
class B {
void bcd() {System.out.println("메소드");}
}
public class RefOfInstanceMethod_Type1_1 {
public static void main(String[] args) {
A a1 = new A() {
@Override
public void bcd() {
B b = new B();
b.bcd();
}
};
A a2 = () -> {
B b = new B();
b.bcd();
};
B b = new B();
A a3 = b::bcd;
}
}
interface A {void abc(int k);};
public class RefOfInstanceMethod_Type1_2 {
public static void main(String[] args) {
A a1 = new A() {
@Override
public void abc(int k) {System.out.println(k);}
};
A a2 = (int k) -> {
System.out.println(k);
};
A a3 = System.out::println;
- 참조방식 2. 정의되어 있는 정적 메소드 참조
interface A {void abc();}
class B {
static void bcd() {System.out.println("메소드");}
}
public class RefOfStaticMethod {
public static void main(String[] args) {
A a1 = new A() {
@Override
B.bcd();
};
A a2 = () -> {
B.bcd();
};
A a3 = B::bcd;
- 첫 번째 매개변수로 전달된 객체의 인스턴스 메소드 참조(인스턴스 메소드 참조)
- 첫 번째 인스턴스 메소드 참조방법 변형 형태
- 첫 번쨰 매개변수 = 인스턴스메소드 포함하는 객체 넘기기
- 클래스명::인스턴스 메소드
- 클래스명이 나온다? -> 정적메소드 or 매개변수로 전달된 인스턴스 메소드 참조
- 메소드의 구분 -> static 여부만으로도 바로 알수 있음
- 인터페이스 매개변수 개수 = 매개변수에 있는 객체 매개변수 + 1;
interface A {void abc(B b, int k);}
class B {
void bcd(int k) {System.out.println(k);}
}
public class RefOfInstanceMethod_Type2_1 {
public static void main(String[] args) {
A a1 = new A() {
@Override
public void abc(B b, int k) {b.bcd(k);}
};
A a2 = (b, k) -> {b.bcd(k);};
A a3 = B::bcd;
interface A {int abc(String str);}
public class RefOfInstanceMethod_Type2_2 {
public static void main(String[] args) {
A a1 = new A() {
@Override
public int abc(String str) {return str.length();}
};
A a2 = (String str) -> str.length();
A a3 = String::length;
생성자 참조
interface A {int[] abc(int len);}
public class RefOfArrayConstructor {
public static void main(String[] args) {
A a1 = new A() {
@Override
public int[] abc(int len) {return new int[len];}
};
A a2 = (int len) -> new int[len];
A a3 = int[]::new;
int[] array1 = a1.abc(3);
int[] array2 = a2.abc(3);
int[] array3 = a3.abc(3);
interface A {B abc();}
class B {
B() {
System.out.println("첫 번째 생성자");
}
B(int k) {
System.out.println("두 번째 생성자");
}
}
public class RefOfClassConstructor_1 {
public static void main(String[] args) {
A a1 = new A() {
@Override
public B abc() {
return new B();
}
};
A a2 = () -> new B();
A a3 = B::new;
interface A {B abc(int k);}
class B {
B() {
System.out.println("첫 번째 생성자");
}
B(int k) {
System.out.println("두 번째 생성자");
}
}
public class RefOfClassConstructor_2 {
public static void main(String[] args) {
A a1 = new A() {
@Override
public B abc(int k) {
return new B(3);
}
};
A a2 = (int k) -> new B(3);
A a3 = B::new;