1. 자바 8에서의 인터페이스의 변화
자바 8에서의 인터페이스의 변화로 큰 두 가지는
인터페이스에 기본 메소드(Default Method)와 스태틱 메소드(Static Method)가 추가된 것입니다.
이 변화로 인해 인터페이스 설계에 많은 변화가 생겼습니다.
자바 8이전에는 설계된 인터페이스를 구현 후 나중에 추가적으로 기능 추가에 대한 요구사항이 생기게 되면
결국에 인터페이스에 새 기능(추상 메소드)를 추가하게 되는데,
그 경우 모든 구현체에서 컴파일 에러가 발생하면서 새로운 추상 메소드를 따로 다 구현해야 되는 상황이 발생하게 됩니다.
그러나 자바 8에선 Default Method의 등장으로 새로 요구되는 기능들을 편하게 추가 할 수 있습니다.
2. 자바 8 인터페이스 예시
[인터페이스]
import java.util.Arrays;
import java.util.List;
public interface CanVendingMachine {
//==자반기 음료수 리스트==//
List list = Arrays.asList("코카콜라", "펩시콜라", "스프라이트");
//==현금결제 추상 메소드==//
void moneyPayment(String money);
//==음료선택 추상 메소드==//
void drinkSelect(String can);
//==카드결제 기본 메소드==//
default void CreditCardPayment(String card) {
if(card.equals("삼성카드")) {
System.out.println("결제가 가능합니다.");
} else {
System.out.println("결제가 불가능한 카드입니다.");
}
}
//==음료 리스트 출력 스태틱 메소드==//
static void DrinkLookup() {
System.out.println("음료의 종류는 다음과 같습니다.");
list.forEach(System.out::println);
}
}
[구현체]
public class MachineImpl implements CanVendingMachine {
@Override
public void moneyPayment(String money) {
System.out.println("잔액: " + money);
}
@Override
public void drinkSelect(String can) {
System.out.println(can + " 선택");
}
}
3. 기본 메소드 (Default Method)
- 인터페이스에 추상 메소드 선언이 아니라 구현체를 제공하는 방법입니다.
- 인터페이스의 구현체 작성 시 재정의(오버라이드) 할 필요 없이 공통 기능을 편하게 개발이 가능합니다.
- 인터페이스의 구현체에서 재정의 할 수도 있습니다. (위에 예시에서 기본 메소드인 CreditCardPayment를 재정의 하였습니다.)
- 단, 구현체가 모르게 구현이 된 기능으로 리스크도 존재합니다. (매우 강력하지만 주의해서 사용해야 할 기능)
[기본 메소드 오버라이드]
public class MachineImpl implements CanVendingMachine {
// ( ... ) 생략
// 기본 메소드는 구현체에서 오버라이드하여 재정의 할 수 있습니다.
@Override
public void CreditCardPayment(String card) {
if(card.equals("삼성카드") || card.equals("국민카드")) {
System.out.println("결제가 가능합니다.");
} else {
System.out.println("결제가 불가능한 카드입니다.");
}
}
}
[리스크]
런타임 에러 발생 가능성
-> 구현체에서 기본 메소드로 잘 못된 매개변수로 호출할 경우 예기치 못한 런타임 에러가 발생할 수 있습니다.
public class MachineImpl implements CanVendingMachine {
// ( ... ) 생략
// 기본 메소드는 구현체에서 오버라이드하여 재정의 할 수 있습니다.
@Override
public void CreditCardPayment(String card) {
if(card.equals("삼성카드") || card.equals("국민카드")) {
System.out.println("결제가 가능합니다.");
} else {
System.out.println("결제가 불가능한 카드입니다.");
}
}
public static void main(String[] args) {
MachineImpl machine = new MachineImpl();
machine.CreditCardPayment(null); // equals 실행 시 NullPointerException 발생
}
}
[조치 방법]
@implSpec 자바독 태그 사용하여 꼭 문서화를 해 줍시다. 그리고 재정의를 이용해서 해결 할 수 있습니다.
public interface CanVendingMachine {
// ( . . . ) 생략
/**
* @implSpec
* 이 구현체는 카드 결제 가능 유무 체크 기능입니다.
* 주의: Null data로 호출 하면 안됩니다.
*/
//==카드결제 기본 메소드==//
default void CreditCardPayment(String card) {
if(card.equals("삼성카드")) {
System.out.println("결제가 가능합니다.");
} else {
System.out.println("결제가 불가능한 카드입니다.");
}
}
}
public class MachineImpl implements CanVendingMachine {
// ( ... ) 생략
// 기본 메소드는 구현체에서 오버라이드하여 재정의 할 수 있습니다.
@Override
public void CreditCardPayment(String card) {
try {
if(card.equals("삼성카드") || card.equals("국민카드")) {
System.out.println("결제가 가능합니다.");
} else {
System.out.println("결제가 불가능한 카드입니다.");
}
} catch (NullPointerException e) {
System.out.println("결제가 불가능한 카드입니다.");
}
}
public static void main(String[] args) {
MachineImpl machine = new MachineImpl();
machine.CreditCardPayment(null); // equals 실행 시 NullPointerException 발생
}
}
4. 스태틱 메소드 (Static Method)
- 기본적인 메서드는 인스턴스가 사용할 수 있는 것이고 해당 인터페이스를 구현한 모든 인스턴스, 해당 타입에 관련되어있는 유틸리티나 헬퍼 메서드를 제공하고 싶은 경우에는 static 메서드를 제공할 수 있습니다.
- 당연한 이야기이지만 Static Method는 구현체에서 재정의 할 수 없습니다.
- 헬퍼 클래스
- 개발자의 편의를 위한 클래스로 어떤 기능을 간편하게 수행하기 위해 사용합니다.
- 유틸리티 클래스
- 인스턴스 메서드와 인스턴스 변수를 제공하지 않고, 정적 메서드와 변수만을 제공하는 클래스로 편의를 위해 사용합니다.
5. 인터페이스의 변화로 인한 API의 변화
- 인터페이스에 기본 메소드의 등장으로 기존 API에 여러 기능들이 추가되었습니다.
- Collection 같은 경우에는 자바 8의 강력한 기능인 stream()과 parallelStream()이 추가되었습니다.
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);
}
}
'Backend > Java' 카테고리의 다른 글
[Java] 데이터 정렬 Null 처리 (nullsFirst(), nullsLast()) (0) | 2021.12.20 |
---|---|
[Java] 자바 8 Iterable API (forEach, spliterator) (0) | 2021.12.19 |
[java] 자바 8 메소드 레퍼런스 (Method Reference) (0) | 2021.12.15 |
[java] 자바 8 람다표현식과 함수형 인터페이스 (함수형 프로그래밍) (0) | 2021.12.12 |
[java] 자바 8 표준 함수형 인터페이스 (java.util.function) (1) | 2021.12.07 |