오늘은 JAVA8에서 변화된 내용 중 하나인 인터페이스의 변화에 대해 알아보도록 하겠다.
기존에 Interface에 대해 공부한 사람들이라면 Interface는 함수에 대한 선언부만 작성할 뿐, body 구현은 이를 implement한 class에서 Override하는 것으로 기억할 것이다.
하지만, JAVA8부터는 이러한 규칙이 조금은 변화되었다고 볼 수 있다.
만약, 어떤 프로젝트를 진행 중, 추가 요청사항으로 인해 공통 사용부에 대한 함수 구현이 필요하다고 가정하자.
만약 interface단에 선언부만 작성한다면, 이를 implement한 모든 class단에서 이를 Override하여 body를 구현해야하는 번거로움이 생긴다.
하지만, JAVA8부터는 interface단에서 선언뿐만 정의할 수 있기 때문에 이러한 번거로움이 조금은 줄어들 수 있다.
코드를 통해 확인해보도록 하자.
public interface CommonInterface{
// 기존 요청사항에 따른 선언부
void getName();
// 추가 요청으로 인해 작성된 구현체
default String getNameToUpperCase(){
return getName().toUpperCase();
}
public class TempClass{
private String name;
public TempClass(String name){
this.name = name;
}
@Override
public String getName(){
return name;
}
}
public class MainClass{
public static voic main(String[] args){
TempClass tmp = new TempClass("hello");
String str = tmp.getNameToUpperCase();
System.out.println(str); // HELLO
}
}
위 코드는 추가 요청사항으로 인해 대문자로 parse한 문자열이 필요한 경우에 default method를 생성한 케이스이다.
이렇게 interface단에서 default method를 생성하게 되면 이를 implement한 class는 해당 method를 기본적으로 가지고 있는 상태가 된다.
이 상태에서 해당 class를 사용하는 Main class에서 interface단에서 구현한 default method를 호출하면서 원하는 결과를 얻는 것이다.
이렇게 default method를 interface단에서 생성하는 것은 구현체 모르게 추가 기능을 만드는 것이기 때문에 컴파일 에러가 아니더라도 런타임 에러가 발생할 수 있는 리스크가 존재한다.
이러한 리스크를 조금이나마 감소시키기 위해 문서화 작업이 필요하고 이때 사용되는 어노테이션이 @implSpec이다.
public interface CommonInterface{
// 기존 요청사항에 따른 선언부
void getName();
/**
* @implSpec name변수로 받은 값에 대해 대문자로 변환해주는 func
*/
default String getNameToUpperCase(){
return getName().toUpperCase();
}
위와 같이 주석에 @implSpec을 통해 해당 method가 어떤 역할로 사용되는지 작성해주면 된다.
- default method, static method는 모두 사용하는 방법은 동일하기 때문에 위에선 default method 위주로 테스트 코드를 작성했지만 static method도 동일한 방식으로 작성 및 사용하면 된다.