[더 자바, Java8] 2. 인터페이스 변화

eunsol Jo·2021년 10월 18일
0

🎱  더 자바, Java8

목록 보기
2/5
post-thumbnail

출처 ‣ 더 자바 Java 8, 백기선 / 인프런

2. 인터페이스의 변화

2.1 인터페이스의 default 메소드 & static 메소드

1) default 메서드 : 인터페이스에 구현부 추가

  • 구현체의 변경없이 새 기능 추가 → 추상메서드를 추가하면, 사전에 해당 인터페이스를 구현한 클래스들에 컴파일 에러 발생 (해당 메서드를 구현하지 않았으므로)
  • 구현체가 모르게 추가된 기능으로 위험성이 있음
    • 런타임 에러 발생 가능 ex. getName()에서 null리턴시 NullpointException
    • 반드시 문서화 필요 (@implSpec)
    • 구현체에서 재정의도 가능
  • Object에서 제공하는 메소드는 재정의가 불가능
    • equals, hashcode...
  • 인터페이스 상속시에 추상메서드로 재정의 가능
  • 같은 이름의 default 메서드를 가지는 인터페이스 두개를 구현시 → 컴파일 에러 ➡️ 오버라이딩하면 사용가능
// 인터페이스
public interface A {
    /**
     * @implSpec 
     * 이 구현체는 getName()가져온 문자열을 대문자로 바꿔 출력한다.
     * */
    default void printNameUpperCase() {
        System.out.println(getName().toUpperCase());
    }
  
    // default String toString() { return ""; } → Object메소드 재정의시 컴파일 에러
    String toString(); // 선언은 가능 → 추상메서드라고 하기엔 모든 interface생성시 기본으로 제공, 특별히 재정의 필요할때만 문서화를 추가해 작성
  
    void printName();
    String getName();
}


// 구현체
public class DefaultA implements A {

    String name;

    public DefaultA(String name) {
        this.name = name;
    }

    @Override
    public void printName() {
        System.out.println(getName());
    }

    @Override
    public String getName() {
        return this.name;
    }
}

// main
public class Main {
    public static void main(String[] args) {
        A a = new DefaultA("esjo");
        a.printNameUpperCase(); // ESJO
    }
}

// 상속
public interface B extends A {
    void printNameUpperCase(); // default메서드의 경우 추상메서드로 재정의가능. 물론, 재정의하지 않아도 된다.
}

// 같은 이름의 default 메서드를 가지는 인터페이스
public interface C {
    default void printNameUpperCase() {
        System.out.println("C");
    };
}

// 컴파일에러! → 오버라이딩 필요
public class DefaultA implements A, C { ... }

2) static 메서드

2.2 자바8 API의 default 메소드 & static 메소드

상속관계 : ArrayList <- List <- Collection <- Iterable

1) Iterable 인터페이스의 default 메소드

a. forEach

/* ArrayList <- List <- Collection <- Iterable(의 default메서드 : forEach)
 * ArrayList에서 재정의되어서 사용
 */
List<String> names = new ArrayList();
names.add("esjo");
names.add("joe");
names.add("cho");

/*names.forEach(s -> {
	System.out.println(s);
});*/

names.forEach(System.out::println);

b. spliterator = 쪼갤수 있는 iterator

  • 병렬 작업시 사용
Spliterator<String> spliterator1 = names.spliterator();
// 절반으로 쪼갬
Spliterator<String> spliterator2 = spliterator1.trySplit();

while (spliterator1.tryAdvance(System.out::println));
System.out.println("====");
while (spliterator2.tryAdvance(System.out::println));

// output
joe
cho
====
esjo

2) Collection 인터페이스의 default 메소드 (Iterable을 상속받음)

a. stream / parallelStream

names.stream().map(String::toUpperCase)
                .filter(s -> s.startsWith("j"))
                .collect(Collectors.toSet());

b. removeIf

names.removeIf(s -> s.startsWith("j"));

c. spliterator

3) Comparator 인터페이스의 default/static 메소드

names.sort(String::compareToIgnoreCase);

a. reversed

Comparator<String> compareToIgnoreCase = String::compareToIgnoreCase;
names.sort(compareToIgnoreCase.reversed());

b. thenComparing

Comparator<String> compareToIgnoreCase = String::compareToIgnoreCase;
names.sort(compareToIgnoreCase.reversed().thenComparing(/*코드작성*/));

c. static reverseOrder / naturalOrder

d. static nullsFirst / nullsLast

e static comparing

profile
Later never comes 👩🏻‍💻

0개의 댓글