목차
익명 클래스는 이름이 없는 클래스를 의미한다.
별도의 클래스 파일을 만들지 않고 코드 내부에서 바로 구현하는 이름 없는 클래스를 의미한다.
인터페이스, 클래스의 구현과 상속을 활용하여 익명 클래스를 사용할 수 있고, 람다는 이러한 익명클래스를 더욱 간결하게 표현하는 역할을 한다.
public interface Calculator {
int sum(int a, int b);
}
public class Main {
public static void main(String[] args) {
Calculator calculator1 = new Calculator() { //익명클래스
@Override
public int sum(int a, int b) {
return a + b;
}
};
int ret1 = calculator1.sum(1, 1);
System.out.println("ret1 = " + ret1);
}
}
코드 결과
ret1 = 2
익명클래스는 코드 내에서 구현하기 때문에 클래스 파일을 만들 필요가 없지만, 코드가 길어진다는 단점이 있다.
람다는 익명 클래스를 보다 더 간결하게 표현하는 문법이다.
또한, 람다는 추상 메서드가 하나만 존재하는 함수형 인터페이스를 대상으로 사용이 가능하다.
// 람다 표현식
Calculator calculator1 = (a, b) -> a + b;
// 익명클래스
Calculator calculator1 = new Calculator() {
@Override
public int sum(int a, int b) {
return a + b;
}
};
@FunctionalInterface //함수형 인터페이스 선언
public interface Calculator {int sum(int a, int b);}
public class Main {
public static void main(String[] args) {
Calculator calculator2 = (a, b) -> a + b;
int ret2 = calculator2.sum(2, 2);
System.out.println("ret2 = " + ret2);
}
}
쉽게 말하면 컴파일 시점에 (a, b) -> a + b부분의 람다 표현식을 보고 sum() 메서드를 가진 익명 클래스를 구현하는 것이다.
정확히는 컴파일러가 람다 표현식을 가지고 해당 함수형 인터페이스를 구현하는 객체로 변환한다.
람다식을 사용할때는 반드시 함수형 인터페이스를 활용하는것이 좋다.
public interface Calculator {
int sum(int a, int b); //선언 가능
int sum(int a, int b, int c); //오버로딩을 통해 선언은 가능하지만 모호성이 발생한다
}
@FunctionalInterface //함수형 인터페이스 선언
public interface Calculator {
int sum(int a, int b);
int sum(int a, int b, int c); //선언시 에러 발생
}
하람다는 하나의 추상 메서드만 구현하기 때문에, @FunctionalInterface 어노테이션을 통해 하나의 메서드만 정의 할 수 있도록 함수형 인터페이스를 사용해야 한다.
public class Main {
public static int calculate(int a, int b, Calculator calculator) {
return calculator.sum(a, b);
}
public static void main(String[] args) {
Calculator cal1 = new Calculator() {
@Override
public int sum(int a, int b) {
return a + b;
}
};
int ret3 = calculate(3, 3, cal1); //이부분에서 변수에 담아 전달됨
System.out.println("ret3 = " + ret3);
}
}
출력결과
ret3 = 6
람다식을 사용하지 않고 직접 객체를 생성해 전달하는 방식이다.
public class Main {
public static int calculate(int a, int b, Calculator calculator) {
return calculator.sum(a, b);
}
public static void main(String[] args) {
Calculator cal2 = (a, b) -> a + b;
int ret4 = calculate(4, 4, cal2); //이부분의 람다를 변수에 담아 전달함
System.out.println("ret4 = " + ret4);
}
}
출력결과
ret4 = 8
람다식을 변수에 담아 매개변수로 전달하는 방식이다. 람다식을 전달할시 calculate()메서드의 매개변수 타입을 보고 Calculator인터페이스를 구현하였는지 추론되기 때문에, 람다식을 전달할 수 있다.
public class Main {
public static int calculate(int a, int b, Calculator calculator) {
return calculator.sum(a, b);
}
public static void main(String[] args) {
int ret5 = calculate(5, 5, (a, b) -> a + b);
System.out.println("ret5 = " + ret5); // 출력: ret5 = 10
}
}
출력결과
ret5 = 10
람다식을 직접 매개변수에 전달하는 방식이다.
이도 마찬가지로 (a, b) -> a + b)라는 람다식을 cacluate()메서드의 매개변수 타입인 Calculator인터페이스를 통해 무슨 기능을 하는지 추론 가능하다.
Calculator cal = (a, b) -> a + b;
Printer printer = a -> System.out.println(a);
Square square = a -> a * a;
Even even = a -> a % 2 == 0;
Upper upper = str -> str.toUpperCase();
Lower lower = str2 -> str2.toLowerCase();
Max max = (a, b) -> a > b ? a : b; //크기비교
BiFunction<Integer, Integer, Integer> sum = (a, b) -> a + b; //두 값을 받아 더한 후, 더한값 리턴
calculate(1, 2, (a, b) -> a + b);