인터페이스의 변화 - 인터페이스 기본 메소드와 스태틱 메소드
package me.whiteship.java8to11;
public interface Foo {
void printName();
default void printNameUpperCase() {
System.out.println("FOO");
}
}
기본 메소드 (Default Methods)
● 인터페이스에 메소드 선언이 아니라 구현체를 제공하는 방법
● 해당 인터페이스를 구현한 클래스를 깨트리지 않고 새 기능을 추가할 수 있다.
인터페이스를 만들다 보면 나중에 인터페이스를 수정할 때 구현체에 모두 구현해줘야 하는 불편함이 있었는데,
default 메서드를 생성해서 이를 대처할 수 있다.
Foo 인터페이스
public interface Foo {
void printName();
default void printNameUpperCase() {
System.out.println(getName().toUpperCase());
}
String getName();
}
printNameUpperCase라는 기본 메서드를 생성했다.
Foo 구현체 DefaultFoo
public class DefaultFoo implements Foo{
String name;
public DefaultFoo(String name) {
this.name = name;
}
@Override
public void printName() {
System.out.println(this.name);
}
@Override
public String getName() {
return this.name;
}
}
Foo 메서드를 상속받았어도 printNameUpperCase를 구현하지 않아도 된다.
App 클래스
Foo foo = new DefaultFoo("keesun");
foo.printName();
foo.printNameUpperCase();
구현체의 메서드 printName,
인터페이스의 기본 메서드 printNameUpperCase 모두 정상적으로 출력된다.
주의점!
● 기본 메소드는 구현체가 모르게 추가된 기능으로 그만큼 리스크가 있다.
○ 컴파일 에러는 아니지만 구현체에 따라 런타임 에러가 발생할 수 있다.
예를 들어 getName()의 구현체가 null을 리턴하면 런타임 에러가 발생할 것이다.
○ 반드시 문서화 할 것. (@implSpec 자바독 태그 사용)
구현체인 DefaultFoo가 재정의하는 방법도 있다.
● Object가 제공하는 기능 (equals, hasCode)는 기본 메소드로 제공할 수 없다.
단, 인터페이스에 추상메서드로 선언하는 것은 상관없다.
String toString();
public interface Bar extends Foo{
void printNameUpperCase();
}
만약 인터페이스(Foo)를 확장한 인터페이스(Bar)에서 Foo의 기본메서드였던 printNameUpperCase()를 사용하고 싶지 않다면, 다시 추상메서드로 재정의하면 된다. 이러면 Bar를 상속받는 구현체들은 저 메서드를 다시 구현해야 한다.
상속받은 2개의 인터페이스가 동일한 이름의 기본메서드를 가졌을 경우
둘중 어떤것을 써야할 지 몰라 컴파일 에러가 발생한다.
이 경우는 직접 해당 메서드를 구현해야 한다.
스태틱 메소드
● 해당 타입 관련 헬퍼 또는 유틸리티 메소드를 제공할 때 인터페이스에 스태틱 메소드를 제공할 수 있다.
static void printAnything() {
System.out.println("Foo");
}
Foo 인터페이스에 스태틱 메서드를 추가한다.
public class App {
public static void main(String[] args) {
/* Foo foo = new DefaultFoo("keesun");
foo.printName();
foo.printNameUpperCase();
*/
Foo.printAnything();
}
}
main에서 출력시 인스턴스 생성 없이도 Foo를 출력하는 것을 확인.
기본메서드는 실무에서 인터페이스를 유지보수할 때 변화를 줄이는데 좋은 방식중 하나가 될 수 있을 것 같다.
참고
● https://docs.oracle.com/javase/tutorial/java/IandI/nogrow.html
● https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html