똑같은 삽질은 2번 하지 말자
Java 8 인터페이스의 변화 본문
한 인터페이스를 여러 클래스에서 구현을 하고 있다고 한다면,
인터페이스에 기능 추가를 위해 메소드를 선언하면 구현하고 있는 모든 클래스들도 구현을 해야한다.
그 말은 그 클래스들 중에 나는 이 기능이 필요없음에도 구현을 해야하는 불필요한 코드들이 추가해야 한다.
그럼 어떻게 해야 불필요한 코드들을 작성하지 않고 인터페이스에 기능추가를 할 수 있을까?
기본 메소드 (Default Methods)
-
인터페이스에 메소드 선언이 아니라 구현체를 제공하는 방법
-
해당 인터페이스를 구현한 클래스를 깨트리지 않고 새 기능을 추가할 수 있다.
-
기본 메소드는 구현체가 모르게 추가된 기능으로 그만큼 리스크가 있다.
-
컴파일 에러는 아니지만 구현체에 따라 런타임 에러가 발생할 수 있다.
-
반드시 문서화 할 것. (@implSpec 자바독 태그 사용)
-
Object가 제공하는 기능 (equals, hasCode)는 기본 메소드로 제공할 수 없다.
-
구현체가 재정의해야 한다.
-
본인이 수정할 수 있는 인터페이스에만 기본 메소드를 제공할 수 있다.
-
인터페이스를 상속받는 인터페이스에서 다시 추상 메소드로 변경할 수 있다.
-
인터페이스 구현체가 재정의 할 수도 있다.
스태틱 메소드
-
해당 타입 관련 헬터 또는 유틸리티 메소드를 제공할 때 인터페이스에 스태틱 메소드를 제공할 수 있다.
기본 메소드로 구현한 대표적인 친구들
public interface Iterable<T> {
/**
* Returns an iterator over elements of type {@code T}.
*
* @return an Iterator.
*/
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
사용해 볼까?
public class GHW {
public static void main(String[] args) {
List<String> name = new ArrayList<>();
name.add("GHW");
name.add("JJang1");
name.add("JJang2");
name.add("Man");
// Parameter 형태는 Consumer<T> Functional Interface다.
name.forEach((s) -> System.out.println(s));
System.out.println("=============");
// 함수 래퍼런스 적용
name.forEach(System.out::println);
Spliterator<String> spliterator = name.spliterator(); // iterator인데 쪼갤수 있는 iterator
Spliterator<String> spliterator1 = spliterator.trySplit();
System.out.println("=============");
while(spliterator.tryAdvance(System.out::println)); // JJang2 Man
System.out.println("=============");
while(spliterator1.tryAdvance(System.out::println)); // GHW JJang1
}
}
이렇게 default 기본 메소드들 덕분에 Java API에도 많은 변화들이 있었다고 한다.
예를 들면 WebMvcConfigurer 인터페이스인데,
/**
* Defines callback methods to customize the Java-based configuration for
* Spring MVC enabled via {@code @EnableWebMvc}.
*
* <p>{@code @EnableWebMvc}-annotated configuration classes may implement
* this interface to be called back and given a chance to customize the
* default configuration.
*
* @author Rossen Stoyanchev
* @author Keith Donald
* @author David Syer
* @since 3.1
*/
public interface WebMvcConfigurer {
/**
* Helps with configuring HandlerMappings path matching options such as trailing slash match,
* suffix registration, path matcher and path helper.
* Configured path matcher and path helper instances are shared for:
* <ul>
* <li>RequestMappings</li>
* <li>ViewControllerMappings</li>
* <li>ResourcesMappings</li>
* </ul>
* @since 4.0.3
*/
default void configurePathMatch(PathMatchConfigurer configurer) {
}
/**
* Configure content negotiation options.
*/
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
//.. 이하 생략
}
이걸 상속받은 WebMvcConfigurerAdapter라는 추상클래스가 있다.
/**
* An implementation of {@link WebMvcConfigurer} with empty methods allowing
* subclasses to override only the methods they're interested in.
*
* @author Rossen Stoyanchev
* @since 3.1
* @deprecated as of 5.0 {@link WebMvcConfigurer} has default methods (made
* possible by a Java 8 baseline) and can be implemented directly without the
* need for this adapter
*/
@Deprecated
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
//..이하 생략
}
Java8 이전에 WebMvcConfigurerAdapter가 있었던 이유는 WebMvcConfigurer를
바로 구현하려고 하면 저 안에 있는 수 많은 메소드들은 다 구현해야 되기 때문에
중간에 추상클래스로 구현을 하고 필요한 메소드 들만 콘크리트 클래스에서 구현해도 되게 하기 위한 기법?
이었다고 한다. 뭐 이제는 필요가 없어졌으니 Deprecated가 붙여져있다.
'Java' 카테고리의 다른 글
Java @ Annotation 애노테이션 이해 (0) | 2020.11.07 |
---|---|
Java 8 Stream (0) | 2020.10.25 |
Java 8 @FunctionalInterface(함수형 인터페이스), 람다 표현식 (0) | 2020.10.18 |
Java Reflection API(리플렉션) (0) | 2020.09.21 |
JIT 컴파일러 이해 (Just-In-Time 컴파일러) (0) | 2020.08.25 |