1. 개요

이 기사에서는 Java 8에서 가장 흥미로운 몇 가지 새로운 기능에 대해 간략히 살펴 보겠습니다.

인터페이스 기본 및 정적 메서드, 메서드 참조 및 선택 사항에 대해 설명합니다.

Java 8 릴리스의 일부 기능인 스트림 API , 람다 표현식 및 기능적 인터페이스 는 별도의 모양이 필요한 포괄적 인 주제이므로 이미 다루었습니다 .

2. 인터페이스 기본 및 정적 방법

Java 8 이전에는 인터페이스에 공용 추상 메서드 만있을 수있었습니다. 모든 구현 클래스가 새 메서드의 구현을 만들도록 강제하지 않고는 기존 인터페이스에 새 기능을 추가 할 수 없었으며 구현을 통해 인터페이스 메서드를 만들 수도 없었습니다.

Java 8부터 인터페이스는 인터페이스 에서 선언 되었음에도 불구하고 정의 된 동작을 갖는 정적기본 메소드를 가질 수 있습니다 .

2.1. 정적 방법

인터페이스의 다음 메소드를 고려하십시오 (이 인터페이스를 Vehicle 이라고 부르겠습니다 ).

static String producer() {
    return "N&F Vehicles";
}

정적 생산자 () 메서드는 인터페이스 내부와 내부에서만 사용할 수 있습니다. 구현 클래스로 재정의 할 수 없습니다.

인터페이스 외부에서 호출하려면 정적 메서드 호출에 대한 표준 접근 방식을 사용해야합니다.

String producer = Vehicle.producer();

2.2. 기본 방법

기본 메서드는 새로운 기본 키워드를 사용하여 선언됩니다 . 이들은 구현 클래스의 인스턴스를 통해 액세스 할 수 있으며 재정의 할 수 있습니다.

Vehicle 인터페이스에 기본 메소드를 추가 하여이 인터페이스 정적 메소드도 호출합니다 .

default String getOverview() {
    return "ATV made by " + producer();
}

이 인터페이스가 VehicleImpl 클래스에 의해 구현되었다고 가정합니다 . 기본 메서드 를 실행하려면 이 클래스의 인스턴스를 만들어야합니다.

Vehicle vehicle = new VehicleImpl();
String overview = vehicle.getOverview();

3. 방법 참조

메서드 참조는 기존 메서드 만 호출하는 람다 식에 대한 더 짧고 읽기 쉬운 대안으로 사용할 수 있습니다. 메서드 참조에는 네 가지 변형이 있습니다.

3.1. 정적 메서드에 대한 참조

정적 메서드에 대한 참조에는 ContainingClass :: methodName 구문이 포함됩니다.

Stream API를 사용 하여 List <String> 의 모든 빈 문자열을 계산해 보겠습니다 .

boolean isReal = list.stream().anyMatch(u -> User.isRealUser(u));

anyMatch () 메서드 에서 람다 식을 자세히 살펴보면 User 클래스 의 정적 메서드 isRealUser (User user)호출 할뿐입니다 . 따라서 정적 메서드에 대한 참조로 대체 할 수 있습니다.

boolean isReal = list.stream().anyMatch(User::isRealUser);

이 유형의 코드는 훨씬 더 많은 정보를 제공합니다.

3.2. 인스턴스 메서드에 대한 참조

인스턴스 메소드에 대한 참조는 다음 구문을 보유합니다. c ontainingInstance :: methodName. 다음 코드 는 입력 매개 변수의 유효성을 검사하는 User 유형의 isLegalName (String string) 메소드를 호출합니다 .

User user = new User();
boolean isLegalName = list.stream().anyMatch(user::isLegalName);

3.3. 특정 유형의 개체의 인스턴스 메서드에 대한 참조

이 참조 메소드는 다음 구문을 사용합니다. C ontainingType :: methodName. 예 ::

long count = list.stream().filter(String::isEmpty).count();

3.4. 생성자에 대한 참조

생성자에 대한 참조는 다음 구문을 사용합니다. ClassName :: new. Java의 생성자는 특별한 메서드이므로 new as a method name을 사용하여 메서드 참조를 적용 할 수도 있습니다 .

Stream<User> stream = list.stream().map(User::new);

4. 옵션 <T>

Java 8 개발자는 NullPointerException (NPE) 이 발생할 가능성이 있으므로 자신이 참조한 값의 유효성을주의 깊게 확인해야했습니다 . 이러한 모든 검사에는 매우 성 가시고 오류가 발생하기 쉬운 상용구 코드가 필요했습니다.

Java 8 Optional <T> 클래스는 NPE 를 얻을 가능성이있는 상황을 처리하는 데 도움이 될 수 있습니다 . T 유형의 개체에 대한 컨테이너로 작동 합니다.이 값이 null 이 아닌 경우이 개체의 값을 반환 할 수 있습니다 . 이 컨테이너 내부의 값이 null이면 NPE 를 던지는 대신 미리 정의 된 작업을 수행 할 수 있습니다 .

4.1. 의 생성 옵션 <T>

Optional 클래스 의 인스턴스 는 정적 메서드를 사용하여 만들 수 있습니다.

Optional<String> optional = Optional.empty();

옵션을 반환합니다 .

String str = "value";
Optional<String> optional = Optional.of(str);

null이 아닌 값을 포함 하는 Optional반환합니다 .

Optional<String> optional = Optional.ofNullable(getString());

반환 옵션을 특정 값 또는 빈과 선택적 매개 변수 인 경우 는 null.

4.2. 선택적 <T> 사용법

예를 들어 List <String> 을 가져올 것으로 예상하고 null 의 경우 ArrayList <String> 의 새 인스턴스로 대체하려고합니다 . W i 번째 8의 코드 자바를 사전에이 같은 것을 할 필요가 :

List<String> list = getList();
List<String> listOpt = list != null ? list : new ArrayList<>();

Java 8에서는 훨씬 짧은 코드로 동일한 기능을 얻을 수 있습니다.

List<String> listOpt = getList().orElseGet(() -> new ArrayList<>());

예전 방식으로 어떤 객체의 필드에 도달해야 할 때 더 많은 상용구 코드가 있습니다. 이 타입의 객체가 가정 사용자 타입의 필드가 주소 필드의와 treet 유형의 문자열. 그리고 어떤 이유로 거리 필드 의 값이 있으면 반환해야하고 거리null이면 기본값 을 반환해야합니다 .

User user = getUser();
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        String street = address.getStreet();
        if (street != null) {
            return street;
        }
    }
}
return "not specified";

선택 사항 으로 단순화 할 수 있습니다 .

Optional<User> user = Optional.ofNullable(getUser());
String result = user
  .map(User::getAddress)
  .map(Address::getStreet)
  .orElse("not specified");

이 예에서 우리는 사용 Map () 호출의 변환 결과에 방법을 getAdress ()를 받는 옵션 <주소>getStreet ()선택적 <문자열>. 이러한 메서드 중 하나가 null을 반환 하면 map () 메서드는 빈 Optional을 반환합니다 .

getter가 Optional <T>를 반환한다고 상상해보십시오 . 따라서 map () 대신 flatMap () 메서드를 사용해야합니다 .

Optional<OptionalUser> optionalUser = Optional.ofNullable(getOptionalUser());
String result = optionalUser
  .flatMap(OptionalUser::getAddress)
  .flatMap(OptionalAddress::getStreet)
  .orElse("not specified");

Optional의 또 다른 사용 사례는 또 다른 예외를 제외 하고 NPE변경하는 것 입니다. 따라서 이전에했던 것처럼 Java 8 이전 스타일로이를 시도해 보겠습니다.

String value = null;
String result = "";
try {
    result = value.toUpperCase();
} catch (NullPointerException exception) {
    throw new CustomException();
}

그리고 Optional <String>을 사용하면 어떨까요? 대답은 더 읽기 쉽고 간단합니다.

String value = null;
Optional<String> valueOpt = Optional.ofNullable(value);
String result = valueOpt.orElseThrow(CustomException::new).toUpperCase();

앱에서 선택 사항 을 사용하는 방법과 목적 은 심각하고 논란이 많은 디자인 결정이며 모든 장단점에 대한 설명은이 문서의 범위를 벗어납니다. 관심이 있다면 더 깊이 파고들 수 있습니다. 인터넷에는이 문제에 관한 흥미로운 기사가 ​​많이 있습니다. 이것이것 하나 가 매우 도움이 될 수 있습니다.

5. 결론

이 기사에서는 Java 8의 몇 가지 흥미로운 새 기능에 대해 간략하게 설명합니다.

물론 많은 Java 8 JDK 패키지 및 클래스에 퍼져있는 다른 많은 추가 및 개선 사항이 있습니다.

그러나이 기사에 설명 된 정보는 이러한 새로운 기능 중 일부를 탐색하고 학습하기위한 좋은 출발점입니다.

마지막으로, 기사의 모든 소스 코드는 GitHub에서 사용할 수 있습니다.