Java default method

해당 글은
자바8 인 액션 의 내용을 포함하고 있습니다.

  • 전통 자바에선 인터페이스와 관련 메서드는 항상 함께한다.
  • Java 7 -> 8로 올라가면서 문제가 발생하지 않을가?
    • 자바 List 인터페이스의 특정 method가 변경되면 기존 List 인터페이스를 구현한 모든 컬렉션프레임워크의 모든 클래스를 고쳐야 한다는 것이다.

자바 8은 이를 어떻게 해결하였는가?

  • 인터페이스의 기본 구현을 제공할수 있도록 default method 제공

기존 인터페이스를 쓰던 클래스들은 디폴트 메서드를 통해 기존 코드를 수정 하지 않고 인터페이스들을 바꿀 수 있다.

대표적인 예를 찾아보자

거의 모든 서비스 비지니스로직은 컬랙션프레임워크를 많이 쓰게 된다 생각한다. 자바8하면 떠오르는 stream!!!!

아래의 예시를 보자

Collection interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public interface Collection<E> extends Iterable<E> {
/**
* Returns a sequential {@code Stream} with this collection as its source.
*
* <p>This method should be overridden when the {@link #spliterator()}
* method cannot return a spliterator that is {@code IMMUTABLE},
* {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
* for details.)
*
* @implSpec
* The default implementation creates a sequential {@code Stream} from the
* collection's {@code Spliterator}.
*
* @return a sequential {@code Stream} over the elements in this collection
* @since 1.8
*/
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}

/**
* Returns a possibly parallel {@code Stream} with this collection as its
* source. It is allowable for this method to return a sequential stream.
*
* <p>This method should be overridden when the {@link #spliterator()}
* method cannot return a spliterator that is {@code IMMUTABLE},
* {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
* for details.)
*
* @implSpec
* The default implementation creates a parallel {@code Stream} from the
* collection's {@code Spliterator}.
*
* @return a possibly parallel {@code Stream} over the elements in this
* collection
* @since 1.8
*/
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
}

디폴트 메서드가 있음으로 과거와 달리 추가된 메소드를 모든 클래스가에서 새로 정의해야하는 일을 사라지게 되었다.

주의점

DoSomethingFirst interface

1
2
3
4
5
6
public interface DoSomethingFirst {

default void doSomething(){
System.out.println("Do something from first");
}
}

DoSomethingSecond interface

1
2
3
4
5
6
public interface DoSomethingSecond extends DoSomethingFirst{

default void doSomething(){
System.out.println("Do something from second");
}
}

DoSomething class

1
2
3
4
5
6
7
public class DoSomething implements DoSomethingFirst, DoSomethingSecond {

public static void main(String[] args) {

new DoSomething().doSomething();
}
}

무엇이 호출될가?
정답은 Do something from second

규칙을 알자!

  1. 클래스가 항상 최우선. 클래스는 슈퍼클래스에서 정의한 메서드가 디폴트 메서드보다 우선이다.
  2. 1번 규칙 이외 상황에선 서브인터페이스가 이긴다. 즉 위의 Second가 First를 상속 받는다면 Second가 이긴다.
  3. 여러 인터페이스를 구현하는 클래스가 명시적으로 디폴트 메서드를 오버라이드하고 호출하면 우선순위가 정해진다.