함수형 인터페이스란, 단 하나의 추상 메서드를 가진 인터페이스를 의미한다. 함수형 인터페이스는 @FunctionalInterface 어노테이션을 사용해 표시할 수 있다.
@FunctionalInterface는 선택 사항이지만 컴파일러에게 해당 인터페이스가 함수형 인터페이스임을 알려주는 역할을 한다.
다음은 함수형 인터페이스 구현과 사용방법에 관한 예시이다.
@FunctionalInterface // 함수형 인터페이스
interface MathOperation {
int operation(int x, int y);
}
public class FunctionInterfaceTest implements MathOperation {
public static void main(String[] args) {
MathOperation mo1 = new FunctionInterfaceTest(); // 함수형 인터페이스 사용 방법 1 : 추상메서드 구현
int result1 = mo1.operation(10, 20);
System.out.println("방법 1 result : " + result1);
System.out.println("++++++++++++++++++");
MathOperation mo2 = new MathOperationImpl();
int result2 = mo1.operation(10, 20);
System.out.println("방법 2 result : " + result2); // 함수형 인터페이스 사용 방법 2 : 구현체 사용
System.out.println("++++++++++++++++++");
MathOperation mo3 = new MathOperation() { // 함수형 인터페이스 사용 방법 3 : (내부)익명클래스 사용(인터페이스는 존재하지만 구현 클래스가 존재하지 않음)
@Override
public int operation(int x, int y) {
return x + y;
}
};
int result3 = mo3.operation(10, 20);
System.out.println("방법 3 result : " + result3);
}
@Override
public int operation(int x, int y) {
return x + y;
}
}
첫번째와 두번째 방법은 일반적으로 인터페이스를 사용하는 방법이다. 세번째 방법은 인터페이스는 존재하지만 실제 구현체는 존재하지 않는 익명클래스를 사용하는 방법이다. 위 코드를 살펴보면 new연산자로 인터페이스를 생성함과 동시에 중괄호를 사용해 바로 메서드를 구현한다.
자바에서는 이미 정의된 메서드를 직접 참조해 람다 표현식을 더욱 간결하게 만들 수 있다. 메서드 참조는 기존 메서드를 재사용하고 코드 중복을 줄이는데 큰 도움을 준다.
1. 정적 메서드 참조 : 클래스명::메서드명
public class IntegerUtilsTest {
public static void main(String[] args) {
Converter<String, Integer> converter = IntegerUtils::stringToInt; // 정적(static) 메서드 참조
int result = converter.convert("123"); // Auto-unboxing
System.out.println("result : " + result);
}
}
2. 인스턴스 메서드 참조 : 객체참조::메서드명
public class StringUtilsTest {
public static void main(String[] args) {
StringUtils stringutils = new StringUtils();
Converter<String, String> converter = stringutils::reverse; // 인스턴스 메서드 참조
String result = converter.convert("hello");
System.out.println("result : " + result);
}
}
3. 특정 객체의 인스턴스 메서드 참조 : 클래스명::메서드명
public class SortCompareTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("김수현", "조용진", "배수지", "박보영", "이상순", "유재석"); // 특정 객체의 인스턴스 메서드 참조
Collections.sort(list, String::compareTo);
System.out.println(list);
for(String name : list) {
System.out.println(name);
}
}
}
4. 생성자 참조 : 클래스명::new
public class PersonFactoryTest {
public static void main(String[] args) {
PersonFactory personFactory1 = Person::new; // 생성자 참조 : Person의 생성자를 참조해 객체 생성
Person person1 = personFactory1.create("홍길동", 25); // 생성자 참조를 활용한 객체생성
System.out.println(person1);
PersonFactory personFactory2 = new PersonFactory() { // 익명 클래스를 활용한 객체생성 : 메서드 참조에 비해 코드가 복잡하고 길다
@Override
public Person create(String name, int age) {
return new Person(name, age);
}
};
Person person2 = personFactory2.create("이몽룡", 28);
System.out.println(person2);
}
}