Java 8의 새로운 기능

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 를 사용하여 목록의 모든 빈 문자열을 계산해 보겠습니다 .

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 stream = list.stream().map(User::new);

4. 옵션

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

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

4.1. 옵션 생성

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

Optional optional = Optional.empty();

옵션을 반환합니다 .

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

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

Optional optional = Optional.ofNullable(getString());

Will return an Optional with a specific value or an empty Optional if the parameter is null.

4.2. Optional Usage

For example, you expect to get a List and in the case of null you want to substitute it with a new instance of an ArrayList. With pre-Java 8's code you need to do something like this:

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

With Java 8 the same functionality can be achieved with a much shorter code:

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

There is even more boilerplate code when you need to reach some object's field in the old way. Assume you have an object of type User which has a field of type Address with a field street of type String. And for some reason you need to return a value of the street field if some exist or a default value if street is 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";

This can be simplified with Optional:

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

In this example we used the map() method to convert results of calling the getAdress() to the Optional and getStreet() to Optional. If any of these methods returned null the map() method would return an empty Optional.

Imagine that our getters return Optional. So, we should use the flatMap() method instead of the map():

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

Another use case of Optional is changing NPE with another exception. So, as we did previously, let's try to do this in pre-Java 8's style:

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

And what if we use Optional? The answer is more readable and simpler:

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

Notice, that how and for what purpose to use Optional in your app is a serious and controversial design decision, and explanation of its all pros and cons is out of the scope of this article. If you are interested, you can dig deeper, there are plenty of interesting articles on the Internet devoted to this problem. This one and this another one could be very helpful.

5. Conclusion

In this article, we are briefly discussing some interesting new features in Java 8.

There are of course many other additions and improvements which are spread across many Java 8 JDK packages and classes.

But, the information illustrated in this article is a good starting point for exploring and learning about some of these new features.

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