Статьи

Что нового в Java 16

Вернуться назад

16 марта 2021

Тэги: Stream API maven Java Collections Java 16

Содержание

  1. Установка
  2. Классы-записи или Lombok больше не нужен
  3. Преобразование Stream в List
  4. Паттерн-матчинг в instanceof
  5. Заключение

Сегодня, 16 марта 2021 года, состоялся релиз новой версии Java 16. Давайте рассмотрим новые конструкции языка, которые в предыдущих версиях находились в статусе preview, а теперь доступны «из коробки» без каких-либо дополнительных настроек.

Установка

Для установки openjdk версии 16 через apt на Ubuntu-подобные системы можно выполнить следующие команды:

sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt update
sudo apt search openjdk
sudo apt install openjdk-16-jdk

Если у вас проект на maven, то для успешной сборки с новой версией Java добавьте в pom.xml следующие параметры:

<properties>
    <maven.compiler.source>16</maven.compiler.source>
    <maven.compiler.target>16</maven.compiler.target>
</properties>

Теперь можно перейти к обзору новых фич.

Классы-записи или Lombok больше не нужен

Самым заметным нововведением в Java 16 является record - новый вид классов. Это специальный вид классов, предназначенный для хранения данных. Если вы знакомы с kotlin, то это аналог data class. Значения всех его полей можно задавать только в момент создания, а затем данные доступны только для чтения через get-методы. Отсюда вытекает, что класс является неизменяемым.

Кроме того, в record не требуется в явном виде определять equals(), hashCode() и toString(). По умолчанию они уже будут корректно учитывать все поля данного класса. Get-методы также не нужно определять явно - они будут называть точно так же, как и исходные поля, без приставки get.

Например, если мы хотим создать сущность, которая хранит в себе информацию о пользователе, то можем сделать это в одну строку:

// неявно наследуется от абстрактного класса java.lang.Record
public record Person(String surname, int age) {}

Тут мы определили класс Person, который неявно наследуется от java.lang.Record с двумя полями: фамилия и возраст. Отсюда следует, что записи не могут наследоваться от других классов, но при этом могут реализовывать интерфейсы.

Инициализация записи ничем не отличается от создания обычного класса через конструктор с параметрами. Get-методы также не нужно описывать явно:

var person1 = new Person("Иванов", 28);
var person2 = new Person("Петров", 30);

// "из коробки" доступны get-методы
System.out.printf("Фамилия пользователя: %s, возраст: %s%n", person1.surname(), person1.age());

Метод toString() по умолчанию возвращает значения полей, а не просто имя самого класса:

System.out.println(person1.toString()); // вернёт строку "Person[surname=Иванов, age=28]"

Метод equals() сравнивает записи не по ссылке, а по значениям полей. То есть если мы создадим новую запись с точно такими же полями, то они будут считаться равными:

System.out.println(person1.equals(person2)); // false, т.к. Иванов не равен Петрову
System.out.println(person1.equals(new Person("Иванов", 28))); // true, т.к. значения полностью одинаковы

Учитывая неизменяемость записей отсюда следует, что записи могут даже использоваться в качестве ключей мапы. Это удобно, когда ключ состоит из нескольких значений. Например, когда мы хотим построить мапу, ключами которой являются точки с координатами x и y.

Поскольку обычно в Java-проектах генерацию get-методов, конструкторов, equals и hashCode отдают на откуп Lombok, то в данном случае можно сказать, что он больше не нужен.

Преобразование Stream в List

До Java 16 мы преобразовывали Stream в список с помощью метода collect() с указанием коллектора. Теперь этого делать не надо, т.к. самая частая операция получила отдельный метод toList().

var list = Stream.of("Linux", "Windows", "Mac")
        .toList(); // до Java 16 .collect(Collectors.toList())

В этом опять прослеживается аналогия с kotlin, где такой метод был изначально.

Паттерн-матчинг в instanceof

Оператор instanceof определяет, является ли данный экземпляр указанным типом или его дочерним классом. После такой проверки мы можем обращаться к методам дочернего класса. При этом больше нет нужды делать явное приведение типа. Достаточно указать лишь новое имя переменной.

Object title = "SOME TEXT"; // строку помещаем в Object

// ...какие-то другие действия..

if (title instanceof String str) {
    // внутри этого if мы обращаемся к title как к строке с помощью алиаса str
    System.out.println(str.toLowerCase()); // вызываем метод класса String
}

Заключение

В этой заметке я рассказал о том, как можно установить Java 16 и какие возможности стали доступны с точки зрения API. Самое главное изменение - это новый вид классов record. Всё описанное выше покинуло статус preview и теперь является частью синтаксиса. При этом я не стал рассказывать про те фичи, которые статуса превью ещё не покинули.



Комментарии

Добавить комментарий

×

devmark.ru