Рубрики
Без рубрики

Новые функции в Java 8

Краткое введение в новые функции Java 8; основное внимание уделяется методам интерфейса по умолчанию и статическим методам, ссылкам на статические методы и необязательным.

Автор оригинала: baeldung.

1. Обзор

В этой статье мы кратко рассмотрим некоторые из наиболее интересных новых функций в Java 8.

Мы поговорим о: интерфейсных методах по умолчанию и статических методах, ссылочных и необязательных методах.

Мы уже рассмотрели некоторые функции выпуска Java 8 – потоковый API , лямбда – выражения и функциональные интерфейсы, поскольку они являются всеобъемлющими темами, которые заслуживают отдельного рассмотрения.

2. Интерфейс по умолчанию и статические методы

До Java 8 интерфейсы могли иметь только общедоступные абстрактные методы. Невозможно было добавить новую функциональность в существующий интерфейс, не заставляя все реализующие классы создавать реализацию новых методов, а также невозможно было создавать методы интерфейса с реализацией.

Начиная с Java 8, интерфейсы могут иметь методы static и default , которые, несмотря на объявление в интерфейсе, имеют определенное поведение.

2.1. Статический метод

Рассмотрим следующий метод интерфейса (назовем этот интерфейс Vehicle ):

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

Статический метод producer() доступен только через интерфейс и внутри него. Он не может быть переопределен реализующим классом.

Чтобы вызвать его вне интерфейса, следует использовать стандартный подход для вызова статического метода:

String producer = Vehicle.producer();

2.2. Метод по умолчанию

Методы по умолчанию объявляются с использованием ключевого слова new default //. Они доступны через экземпляр реализующего класса и могут быть переопределены.

Давайте добавим метод default в наш интерфейс Vehicle , который также вызовет метод static этого интерфейса:

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

Предположим, что этот интерфейс реализован классом VehicleImpl. Для выполнения метода default должен быть создан экземпляр этого класса:

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

3. Ссылки на методы

Ссылка на метод может использоваться в качестве более короткой и читаемой альтернативы для лямбда-выражения, которое вызывает только существующий метод. Существует четыре варианта ссылок на методы.

3.1. Ссылка на статический метод

Ссылка на статический метод содержит следующий синтаксис: Содержащий класс::имя метода.

Давайте попробуем подсчитать все пустые строки в List с помощью Stream API.

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

Взгляните поближе на лямбда-выражение в методе any Match () , оно просто вызывает статический метод является реальным пользователем(User user) класса User . Таким образом, его можно заменить ссылкой на статический метод:

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

Этот тип кода выглядит гораздо более информативным.

3.2. Ссылка на метод экземпляра

Ссылка на метод экземпляра содержит следующий синтаксис: c содержащий экземпляр::имя метода. Следующий код вызывает метод является юридическим именем(строка string) типа User , который проверяет входной параметр:

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

3.3. Ссылка на Метод экземпляра Объекта определенного типа

Этот ссылочный метод использует следующий синтаксис: C содержащий тип::имя метода. Пример::

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

3.4. Ссылка на конструктор

Ссылка на конструктор принимает следующий синтаксис: className :: new. Поскольку конструктор в Java является специальным методом, ссылка на метод также может быть применена к нему с помощью new | в качестве имени метода .

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);

Возвращает Необязательный , содержащий ненулевое значение.

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

Возвращает Необязательный с определенным значением или пустой Необязательный , если параметр равен null.

4.2. Необязательное использование

Например, вы ожидаете получить List , а в случае null вы хотите заменить его новым экземпляром ArrayList. С кодом до Java 8 вам нужно сделать что-то вроде этого:

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

С Java 8 та же функциональность может быть достигнута с помощью гораздо более короткого кода:

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

Существует еще больше шаблонного кода, когда вам нужно добраться до поля какого-либо объекта старым способом. Предположим, у вас есть объект типа User , который имеет поле типа Address с полем s threat типа String. И по какой-то причине вам нужно вернуть значение поля street , если оно существует, или значение по умолчанию, если street равно 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 = Optional.ofNullable(getUser());
String result = user
  .map(User::getAddress)
  .map(Address::getStreet)
  .orElse("not specified");

В этом примере мы использовали метод map() для преобразования результатов вызова getAdress() в Необязательный<Адрес> и get Street() в Необязательный<Строка>. Если какой-либо из этих методов вернет null , метод map() вернет пустой Необязательный.

Представьте, что наши геттеры возвращают Необязательный. Таким образом, мы должны использовать метод flatMap() вместо map():

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

Другой вариант использования Необязательно изменяется NPE с другим исключением. Итак, как и ранее, давайте попробуем сделать это в стиле до Java 8:

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

А что, если мы используем Необязательный ? Ответ более читабельный и простой:

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

Обратите внимание, что то, как и с какой целью использовать Необязательно в вашем приложении, является серьезным и спорным дизайнерским решением, и объяснение всех его плюсов и минусов выходит за рамки этой статьи. Если вам интересно, вы можете копнуть глубже, в интернете есть много интересных статей, посвященных этой проблеме. Это одно и это другое было бы очень полезно.

5. Заключение

В этой статье мы кратко обсудим некоторые интересные новые функции в Java 8.

Конечно, есть много других дополнений и улучшений, которые распространяются на многие пакеты и классы Java 8 JDK.

Но информация, проиллюстрированная в этой статье, является хорошей отправной точкой для изучения и изучения некоторых из этих новых функций.

Наконец, весь исходный код статьи доступен на GitHub.