온라인 학습/더 자바, Java 8 강의

2. 인터페이스의 변화 - default method, static method

2022. 11. 10. 10:33

<1> 인터페이스 기본 메소드와 스태틱 메소드

 

✔ 기본 메소드 (Default Methods)

  • 인터페이스에 메소드 선언이 아니라 구현체를 제공하는 방법
  • 해당 인터페이스를 구현한 클래스를 깨트리지 않고 새 기능을 추가할 수 있다.
  • 기본 메소드는 구현체가 모르게 추가된 기능으로 그만큼 리스크가 있다.
    • 컴파일 에러는 아니지만 구현체에 따라 런타임 에러가 발생할 수 있다.
    • 반드시 문서화 할 것. - @implSpec 자바독 태그 사용
  • Object가 제공하는 기능 (equals, hashCode, toString)는 기본 메소드로 제공할 수 없다.
    • 구현체가 재정의해야 한다.
  • 본인이 수정할 수 있는 인터페이스에만 기본 메소드를 제공할 수 있다.
  • 인터페이스를 상속받는 인터페이스에서 다시 추상 메소드로 변경할 수 있다. 
  • 인터페이스 구현체가 재정의 할 수도 있다.

 

 

 

1) default 키워드로, 한 인터페이스를 구현한 여러 클래스에 공통 기능을 에러 없이 추가할 수 있다. 

(좌)에러 발생 (우)default 키워드 추가

이 인터페이스 Foo를 구현했던 모든 클래스들이 전부 컴파일 에러가 발생한다.

추가한 추상 메서드 printNameUpperCase를 구현하지 않았기 때문이다.

default 키워드 추가하여 에러 없이 특정 기능을 제공할 수 있다.

 

 

Java가 제공하는 Collection에서 보면, removeIf라는 기본 메소드(default method)를 컬렉션이 제공하고 있다.

이 컬렉션의 모든 하위 클래스는 전부 이 기능을 갖게 될 것이다.

Predicate이니까 true/false로 리턴한다. true에 해당하는 요소를 걸러낸다.

 

 

예)

Foo 인터페이스

 

DefaultFoo 클래스

 

App 클래스

 

출력 결과 :

keesun

KEESUN

 

 

2) 반드시 문서화 해야 한다. (자바독 태그 @impleSpec)

getName에 어떤 값이 올지 모른다. 예를 들어 null값이 오면 동작하지 않는다.

그렇기 때문에 이해하고 사용할 수 있도록 문서화를 해줘야 한다. 

 

 

Javadoc이란?

  • Java 소스 코드에서 HTML 형식의 API 문서를 생성하기 위해 Sun Microsystems에서 작성한 문서 생성기
  • Javadoc은 소스코드 파일에서 문서화 주석이라는 특수한 형태로 기술된 설명을 추출해 API 문서로 변환해준다.

 

 

 

3) 만약 문제가 생긴다 해도 오버라이딩으로 재정의 해줄 수 있다. 

 

 

4) Object가 제공하는 메소드는 기본 메소드로 제공할 수 없다. ex) equals, hashCode, toString, ...

컴파일 에러 발생

 

 

5) 인터페이스를 상속받는 인터페이스에서 다시 추상 메소드로 변경할 수 있다.

예)

Bar에서 Foo가 제공하는 기본 구현체 printNameUpperCase를 제공하고 싶지 않을 때, Bar에서 추상 메서드로 선언해주면 된다.

추상 메서드로 선언해주지 않으면 Bar를 구현하는 모든 인스턴스들도 기본적으로 제공이 된다.

추상 메서드로 선언했는데 Bar를 구현하는 모든 인스턴스들이 printNameUpperCase를 쓰고 싶으면 다시 재정의 해줘야 한다.

 

 

6) 충돌 시 직접 오버라이딩 (diamond problem)

예)

Foo와 Bar 둘 다 같은 이름의 default 메소드가 있을 때,

DefaultFoo가 두 인터페이스를 참조하려 하면 컴파일 에러가 발생한다.

자바가 둘 중 어떤 걸 써야 할지 판단을 못한다.

컴파일 에러 발생

 

이럴 때는 직접 오버라이딩 하여 재정의 해주면 된다.

직접 오버라이딩 해주면 된다

 

 


✔ 스태틱 메소드

  • 해당 타입 관련 헬퍼 또는 유틸리티 메소드를 제공할 때 인터페이스에 스태틱 메소드를 제공할 수 있다.

 

예)

Foo 인터페이스에 있는 스태틱 메소드 printAnything을 호출해서 쓸 수 있다.

Foo 인터페이스

 

App 클래스

 

출력:

Foo

 

 


<2> 자바8 API의 기본 메소드와 스태틱 메소드

자바 8에서 추가한 기본 메소드로 인한 API 변화

 

  • Iterable의 기본 메소드
    • forEach()
    • spliterator() : 분할 할 수 있는 반복자. 즉, 쪼갤 수 있는 이터레이터.

 

forEach()
메소드 레퍼런스로 한다면
for로 해도 되지만 forEach가 간결함

 

출력:

keesun

whiteship

toby

foo

 

 

public interface Spliterator<T> {
    // 탐색 여부 반환
    boolean tryAdvance(Consumer<? super T> action);

    // 모든 요소가 처리되거나 예외 throw 될 때 까지 지정 작업 수행
    default void forEachRemaining(Consumer<? super T> action) {
        do { } while (tryAdvance(action));
    }
    
    // Spliterator 일부 요소를 분할해서 새로운 Spliterator 생성
    Spliterator<T> trySplit();
    
    // 남은 요소 개수
    long estimateSize();
    
    // ( . . . ) 생략
}

spliterator

 

출력:

toby

foo

============

keesun

whiteship

 

 

  • Collection의 기본 메소드
    • 사실상 컬렉션이 이터러블 상속받는 인터페이스라서 거의 같다고 보면 된다. 
    • stream() / parallelStream()
    • removeIf(Predicate)
    • spliterator()

 

stream

 

출력:

1

 

removeIf

 

출력:

whiteship

toby

foo

 

 

  • Comparator의 기본 메소드 및 스태틱 메소드
    • reversed()
    • thenComparing()
    • static reverseOrder() / naturalOrder()
    • static nullsFirst() / nullsLast()
    • static comparing()

 

출력:

foo

keesun

toby

whiteship

 

reversed

 

출력:

whiteship

toby

keesun

foo

 

thenComparing

 

 

 

 

 

* 백기선 님의 인프런 강의 <더 자바, Java 8>을 듣고 정리한 내용입니다.

강의 정보: https://www.inflearn.com/course/the-java-java8/

 

참고

https://veneas.tistory.com/entry/Java-%EC%9E%90%EB%B0%94-8-Iterable-API-forEach-spliterator

https://kangworld.tistory.com/208
https://docs.oracle.com/javase/tutorial/java/IandI/nogrow.html
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html
https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html
https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html
https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html