Ми вже встигли звикнути до того, що новий реліз JDK з'являється раз на півроку. Поки що такий підхід себе виправдав, а переживання деяких розробників, мовляв, вони не встигатимуть за оновленнями, виявабося марними: піврічних змін трохи і вони не такі глобальні, як раніше. Ну а програмісти-початківці можуть і зовсім не помітити нововведення. Тим не менш, майбутнім розробникам ПЗ краще бути в курсі нововведень. У цій статті ми традиційно опишемо прийняті пропозиції щодо розширення (JEP). Java 13 включає лише п'ять JEP'ів і 76 нових елементів базової бібліотеки (з яких майже половина — прості доповнення до пакету java.io).
JEP 355 : Text Blocks (Preview)
Почнемо із зміни синтаксису мови. Найзначніша з них – це текстові блоки. Вони дозволяють уникати екранування символів та вміють форматувати рядки. Можливо, ви пам'ятаєте , що в JDK 12 так і не з'явилася очікувана фіча Raw String Literals (JEP 326) для роботи з рядковими літералами. У Java 13 їй на зміну прийшов JEP 355 із його текстовими блоками. Ви, найімовірніше, пам'ятаєте, що Java рядок обгорнуто в подвійні лапки. Це добре, але проблема в тому, що рядок не може займати більше однієї лінії вихідного файлу (щоб не плутати з Java-рядком, тут називатимемо рядок файлу "лінією"). Що ж, підемо в обхід і використовуємо, наприклад, символ\n
якщо потрібно розрив, або конкатенацію багаторядкових виразів. Не дуже гарно виходить! Особливо громіздко виглядають текстові літерали із вбудованими фрагментами HTML, XML, SQL чи JSON. Всі ці екранування, конкатенації, ручне редагування робить код незручним для написання і важко читати. Текстові блоки намагаються вирішити цю проблему. Вони починаються ЕЕЕ ... з потрійних подвійних лапок і закінчуються ними ж (знаю, звучить не дуже). Все, що знаходиться між лапками, інтерпретується як частина рядка, включаючи переклади на нову лінію. Текстові блоки можна використовувати точно так, як стандартні текстові літерали, Java скомпілює код однаково. Відкриваючі лапки повинні супроводжуватися обмежувачем рядка; текстові блоки не можна використовувати в одну лінію, тому код
String smallBlock = """Only one line""";
призведе до таких помилок:
TextBlock.java:3: error: illegal text block open delimiter sequence, missing line terminator
String smallBlock = """Text Block""";
^
TextBlock.java:3: error: illegal text block open delimiter sequence, missing line terminator
String smallBlock = """Text Block""";
^
Простий HTML-фрагмент тепер можна написати так:
String htmlBlock = """
<html>
<body>
<p>JavaRush Web page</p>
</body>
<html>
""";
Згадаємо кілька тонкощів, про які краще знати під час використання текстових блоків. Розташування лапок виявляється важливим: воно визначає, як обробляється випадковий пробіл. У наведеному вище прикладі лапки, що закривають, вирівняні з відступом тексту HTML. У цьому випадку компілятор видалить прогалини відступу, і в результаті ми отримаємо такий рядок:
<html>
<body>
<p>My web page</p>
</body>
</html>
Зверніть увагу:такий рядок міститиме нову лінію в кінці рядка. Якщо вона не потрібна, закриваючі лапки “”” можна поставити безпосередньо після тега</html>. Якщо ми перемістимо лапки, що закривають, ближче до лівого поля, це змінить кількість віддалених відступів. Якби ми перемістабо їх на два пробіли вліво, ми додали б два пробіли для відступу до кожної лінії рядка. Переміщення до лівого краю призведе до збереження всіх відступів. Переміщення лапок далі вправо не матиме жодного ефекту і не додасть більше відступів. У версію JDK 13 текстові блоки потрапабо як прев'ю-фічі. Це означає, що вони поки що не включені у відповідну специфікацію мови Java. Тобто незрозуміло, чи стане ця фіча постійною частиною мови, чи вона тут лише гість. В даний час розробники можуть протестувати фічу та висловити думку про неї. Від нього і залежатиме доля текстових блоків: фічу можуть покращити, а якщо вона не сподобається — то й зовсім вилучити. Якщо ви хочете випробувати текстові блоки на практиці, пам'ятайте, що прев'ю-фічі потрібно явно включати для компіляції та виконання. Компіляція:
javac --enable-preview --release 13 TextBlock.java
Щоб запустити програму, потрібно увімкнути функції попереднього перегляду:
java --enable-preview TextBlock
У класі String
є три нові методи, які доповнюють цю зміну мови:
formatted()
: форматує рядок, використовуючи сам рядок як рядок формату. Еквівалентний викликуformat(this, args)
stripIndent()
: видаляє випадкові пробіли з рядка. Це корисно, якщо ви читаєте багаторядкові рядки і хочете застосувати такий самий виняток випадкових прогалин, як і у разі явного оголошення.translateEscapes()
: повертає рядок з escape-послідовностями (наприклад,\ r
), переведеними у відповідне значення Unicode.
@PreviewFeature
допомогло б з подібними ситуаціями, але поки що така вона не входить до JDK (хоча з високою ймовірністю вона з'явиться в JDK 14).
JEP 354 : Switch Expression (Preview)
У Java 12 з'явилася пропозиція про нову форму написання виразів з оператором switch - JEP 325 . Воно виявилося найпершою прев'ю-фічею і її доля доводить, що виносити пропозиції на суд користувачів - чудова ідея. До JDK 12switch
можна було використовувати лише як оператор, який виконує дію, але не повертає результату. А ось у Java 12 дозволила використовувати switch
як вираз, що повертає результат, який можна присвоїти змінній. Були й інші зміни в синтаксисі операторів case всередині switch
. Давайте розглянемо приклад із JEP, щоб розібратися, як це працює.
int numberOfLetters;
switch(dayOfWeek) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numberOfLetter = 6;
break;
case TUESDAY
numberOfLetter = 7;
break;
case THURSDAY
case SATURDAY
numberOfLetter = 8;
break;
case WEDNESDAY
numberOfLetter = 9;
break;
default:
throw new IllegalStateException("Huh?: " + day);
}
У цьому прикладі ми використовуємо значення dayOfWeek
для визначення значення numberOfLetters
. Через особливості роботи оператора switch
, цей код — не найкрасивіший і легко наробити помилок. По-перше, якщо ми забудемо застосувати оператор break
для кожної групи case-міток, ми за замовчуванням перейдемо до наступної групи міток. Це може призвести до помилок, які важко знайти. По-друге, ми повинні визначити кожну групу case-міток. Якщо забудемо, то, зрозуміло, отримаємо помилку компілятора, однак такий варіант не ідеальний. Також наш код дуже багатослівний, оскільки кожне значення dayOfWeek
має мати свою власну case-мітку. Використовуючи новий синтаксис, ми отримуємо набагато чистіший і менш схильний до помилок код:
int numberOfLetters = switch (dayOfWeek) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
default -> throw new IllegalStateException("Huh?: " + day);
};
Тепер нам потрібно зробити привласнення тільки один раз (з повертається switch
значенням) і можна використовувати список, що розділяється комами, для case-міток. І оскільки ми не використовуємо оператор break
, то усуваємо пов'язані з ним проблеми. Синтаксис виразу switch
дозволяє використовувати синтаксис більш старого стилю, тому JDK 12 ми можемо написати і так:
int numberOfLetters = switch (dayOfWeek) {
case MONDAY:
case FRIDAY:
case SUNDAY:
break 6;
case TUESDAY
break 7;
case THURSDAY
case SATURDAY
break 8;
case WEDNESDAY
break 9;
default:
throw new IllegalStateException("Huh?: " + day);
};
На думку Java-спільноти, перевантаження використання break
для вказівки значення, що повертається, може збивати з пантелику. Мова Java також дозволяє використовувати break
(і continue
) з позначкою на зразок оператора безумовного переходу goto
. У JEP 354 було змінено подібне використання break
, так що Java 13 наш код дещо змінюється:
int numberOfLetters = switch (dayOfWeek) {
case MONDAY:
case FRIDAY:
case SUNDAY:
yield 6;
case TUESDAY
yield 7;
case THURSDAY
case SATURDAY
yield 8;
case WEDNESDAY
yield 9;
default:
throw new IllegalStateException("Huh?: " + day);
};
Наступні три JEP'а пов'язані з віртуальною машиною Java.
JEP 350 Dynamic CDS Archive
Це розширення дозволяє провести динамічне архівування класів наприкінці виконання Java-програми. CDS або Class Data Sharing дозволяє запакувати всі класи, що запускаються при старті, в спеціальний архівclass data sharing
, використовуючи список цих самих класів за замовчуванням. Це призводить до суттєвого прискорення запуску додатків та економії оперативної пам'яті. Раніше використання AppCDS було багатоетапним процесом, що включає створення списку відповідних класів та використання цього списку для створення архіву, який буде використовуватися для подальших запусків. Тепер все, що потрібно, - це один запуск програми з прапором -XX: ArchiveClassesAtExit
, що вказує місце, куди буде записано архів. При такому підході класи автоматично упаковуються до архіву після нормальної зупинки програми.
JEP 351 ZGC : Uncommit unused memory
Рік тому в JDK 11 бид представлений ZGC - експериментальний збирач сміття, що масштабується, з низькою затримкою. Спочатку ZGC поводився досить дивно: він не дозволяв повернути пам'ять операційній системі, навіть якщо вона вже була не потрібна. Для деяких середовищ, наприклад, для контейнерів, де ресурси використовуються кількома службами одночасно, це може обмежувати масштабованість та ефективність системи. Купа ZGC складається з так званих ZPages. Коли ZPages очищаються під час циклу збору сміття, вони повертаються до кешу ZPageCache. ZPages у цьому кеші впорядковано за порядком давності використання. Java 13 ZGC повертатиме в операційну систему сторінки, які були визначені як ті, що не використовувалися досить довго. Таким чином, їх можна буде використовувати повторно для інших процесів.JEP 353 Reimplement the legacy Socket API
Обидві реалізації APIjava.net.Socket
відносяться java.net.ServerSocket
ще JDK 1.0. У цій, та й у всіх наступних JDK, реалізація цих API-інтерфейсів використовує кілька методів (таких, як використання стека потоків як буфер введення-виведення), які роблять їх негнучкими і складними в обслуговуванні. Щоб вирішити цю проблему, JDK 13 надали нову реалізацію NioSocketImpl
. Вона більше не вимагає нативного коду, тим самим спрощуючи портування на різні платформи. Цей клас також використовує існуючий механізм буферного кешу (за винятком використання стека потоків для цієї мети) і блокування java.util.concurrent
, а не синхронізовані методи. Це спростить інтеграцію з файберами з Project Loom .
Нові API
Ми вже згадували раніше, що Java 13 включає 76 нових API в бібліотеках базових класів. Вони охоплюють такі області:- Оновлення підтримки Unicode.
- Три нові методи
String
для підтримки текстових блоків (див. опис JEP 255 вище). - Класи
java.nio
тепер мають абсолютні (на відміну від відносних)get
таset-методи. Вони, як і базовий абстрактний клас Buffer
, включають методslice()
вилучення частини буфера. - Метод
force()
класуMappedByteBuffer
примусово записує розділ буфера у його резервне сховище. nio.FileSystem
додає три нові перевантажені формиnewFileSystem()
для доступу до вмісту як файлової системи.- З'явився
javax.annotation.processing.ProcessingEnvironment
новий цікавий метод.isPreviewEnabled()
. Він повідомить про те, чи включені preview-фічі. Це цікаво тому, що згадана вище інструкція@PreviewFeature
не буде доступна до виходу JDK 14. DocumentBuilderFactory
іSAXParserFactory
отримуютьjavax.xml.parsers
три нових методу для створення екземплярів, що підтримують простір імен.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ