18
Окт
2019

Всё о Java 13: погружение в мир обновлений

Немного покопавшись в новинках, с небольшим опозданием спешим порадовать крутыми удобствами от Oracle. Разберем пять JEP-ов (JDK Enchancement Proposal), пришедших к нам в этом апдейте.

JEP 350 Dynamic CDS Archives

Этот JEP улучшил JEP 310 (Application Class-Data Sharing), представленный в Java 10 для упрощения процесса динамического создания CDS-архивов.

CDS можно создать, используя директиву -XX: ArchiveClassesAtExit:

$ java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello

Есть такой вариант запуска приложения с архивом, созданным выше:

$  bin/java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello

Идея Class Data Sharing (CDS) – это возможность повышения производительности запуска путем создания архивированных классов один раз, а затем повторно использовать их так, чтобы JVM не пришлось пересоздавать их снова.

Для получения более полной информации обратись в официальный хелп.

JEP 351 Uncommit Unused Memory

В материалы Java 11 был добавлен JEP 333 (ZGC: A Scalable Low-Latency Garbage Collector), который обеспечивает короткие промежутки времени в процессе очистки памяти. Но есть одно "но": он не возвращал неиспользуемую память в ОС, даже если эта память не использовалась в течение длительного времени.

Данный JEP улучшает ZGC, и теперь неиспользованная динамическая память возвращается операционной системе.

Для получения более полной информации обратись в официальный хелп.

JEP-353 Reimplement the Legacy Socket API

Основные реализации java.net.Socket и java.net.ServerSocket очень древние и уходят корнями в JDK 1.0. Код состоит из смеси устаревшей Java и C, которую трудно поддерживать и отлаживать. Этот JEP представляет обновленные реализации для API сокетов, и теперь в Java 13 они будут по дефолту.

До новой версии Java использовался PlainSocketImpl для SocketImpl:

public class ServerSocket implements java.io.Closeable {

    /**

     * Имплементация этого Socket.

     */

    private SocketImpl impl;

}

В Java 13 вводится новый класс NioSocketImpl на замену PlainSocketImpl. Но если что-то пойдет не так, есть возможность вернуться к старой реализации.

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class JEP353 {

    public static void main(String[] args) {

        try (ServerSocket serverSocket = new ServerSocket(8888)){

            boolean running = true;
            while(running){

                Socket clientSocket = serverSocket.accept();
                //сделай что-нибудь с clientSocket
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

Посмотрите на трассировку загрузки класса NioSocketImpl для сокета, описанного выше:

D:\test>javac JEP353.java

D:\test>java JEP353

D:\test>java -XX:+TraceClassLoading JEP353  | findStr Socket

[0.040s][info   ][class,load] java.net.ServerSocket source: jrt:/java.base
[0.040s][info   ][class,load] jdk.internal.access.JavaNetSocketAccess source: jrt:/java.base
[0.040s][info   ][class,load] java.net.ServerSocket$1 source: jrt:/java.base
[0.040s][info   ][class,load] java.net.SocketOptions source: jrt:/java.base
[0.040s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
[0.044s][info   ][class,load] java.net.SocketImpl$$Lambda$1/0x0000000800ba0840 source: java.net.SocketImpl
[0.047s][info   ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base

[0.047s][info   ][class,load] sun.nio.ch.NioSocketImpl source: jrt:/java.base

[0.047s][info   ][class,load] sun.nio.ch.SocketDispatcher source: jrt:/java.base
[0.052s][info   ][class,load] java.net.SocketAddress source: jrt:/java.base
[0.052s][info   ][class,load] java.net.InetSocketAddress source: jrt:/java.base
[0.052s][info   ][class,load] java.net.InetSocketAddress$InetSocketAddressHolder source: jrt:/java.base
[0.053s][info   ][class,load] sun.net.ext.ExtendedSocketOptions source: jrt:/java.base
[0.053s][info   ][class,load] jdk.net.ExtendedSocketOptions source: jrt:/jdk.net
[0.053s][info   ][class,load] java.net.SocketOption source: jrt:/java.base
[0.053s][info   ][class,load] jdk.net.ExtendedSocketOptions$ExtSocketOption source: jrt:/jdk.net
[0.053s][info   ][class,load] jdk.net.SocketFlow source: jrt:/jdk.net
[0.053s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions source: jrt:/jdk.net
[0.053s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions$1 source: jrt:/jdk.net
[0.054s][info   ][class,load] jdk.net.ExtendedSocketOptions$1 source: jrt:/jdk.net
[0.054s][info   ][class,load] sun.nio.ch.NioSocketImpl$FileDescriptorCloser source: jrt:/java.base
[0.055s][info   ][class,load] java.net.Socket source: jrt:/java.base

А теперь сравни трассировку с более старой реализацией:

D:\test>java -Djdk.net.usePlainSocketImpl -XX:+TraceClassLoading JEP353  | findStr Socket

[0.041s][info   ][class,load] java.net.ServerSocket source: jrt:/java.base
[0.041s][info   ][class,load] jdk.internal.access.JavaNetSocketAccess source: jrt:/java.base
[0.041s][info   ][class,load] java.net.ServerSocket$1 source: jrt:/java.base
[0.041s][info   ][class,load] java.net.SocketOptions source: jrt:/java.base
[0.041s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
[0.045s][info   ][class,load] java.net.SocketImpl$$Lambda$1/0x0000000800ba0840 source: java.net.SocketImpl
[0.048s][info   ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base
[0.048s][info   ][class,load] java.net.AbstractPlainSocketImpl source: jrt:/java.base

[0.048s][info   ][class,load] java.net.PlainSocketImpl source: jrt:/java.base

[0.048s][info   ][class,load] java.net.AbstractPlainSocketImpl$1 source: jrt:/java.base
[0.050s][info   ][class,load] sun.net.ext.ExtendedSocketOptions source: jrt:/java.base
[0.050s][info   ][class,load] jdk.net.ExtendedSocketOptions source: jrt:/jdk.net
[0.050s][info   ][class,load] java.net.SocketOption source: jrt:/java.base
[0.051s][info   ][class,load] jdk.net.ExtendedSocketOptions$ExtSocketOption source: jrt:/jdk.net
[0.051s][info   ][class,load] jdk.net.SocketFlow source: jrt:/jdk.net
[0.051s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions source: jrt:/jdk.net
[0.051s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions$1 source: jrt:/jdk.net
[0.051s][info   ][class,load] jdk.net.ExtendedSocketOptions$1 source: jrt:/jdk.net
[0.051s][info   ][class,load] java.net.StandardSocketOptions source: jrt:/java.base
[0.051s][info   ][class,load] java.net.StandardSocketOptions$StdSocketOption source: jrt:/java.base
[0.053s][info   ][class,load] sun.net.ext.ExtendedSocketOptions$$Lambda$2/0x0000000800ba1040 source: sun.net.ext.ExtendedSocketOptions
[0.056s][info   ][class,load] java.net.SocketAddress source: jrt:/java.base
[0.056s][info   ][class,load] java.net.InetSocketAddress source: jrt:/java.base
[0.058s][info   ][class,load] java.net.InetSocketAddress$InetSocketAddressHolder source: jrt:/java.base
[0.059s][info   ][class,load] java.net.SocketCleanable source: jrt:/java.base

Для получения более полной информации обратись в официальный хелп.

JEP-354 Switch Expressions (Preview)

Данные Java новости изменяют предложенное улучшение поведения оператора switch из JEP-325. Помните, как ранее switch выполнял какое-либо действие по условию? Ну вот теперь результат выполнения можно положить в переменную. Круто, правда? :)

До Java 12 традиционный оператор switch мог вернуть значение в таком формате:

private static String getText(int number) {
        String result = "";
        switch (number) {
            case 1, 2:
                result = "один или два";
                break;
            case 3:
                result = "три";
                break;
            case 4, 5, 6:
                result = "четыре или пять или шесть";
                break;
            default:
                result = "хз";
                break;
        };
        return result;
    }

В Java 12 стало возможно использовать break для возврата значения:

private static String getText(int number) {
        String result = switch (number) {
            case 1, 2:
                break "один или два";
            case 3:
                break "три";
            case 4, 5, 6:
                break "четыре или пять или шесть";
            default:
                break "хз";
        };
        return result;
    }

В Java 13 вышеуказанный код из Java 12 не скомпилится. Нужно использовать yield для возврата значения:

private static String getText(int number) {
        return switch (number) {
            case 1, 2:
                yield "один или два";
            case 3:
                yield "три";
            case 4, 5, 6:
                yield "четыре или пять или шесть";
            default:
                yield "хз";
        };
    }

Для получения более полной информации обратись в официальный хелп.

JEP-355 Text Blocks (Preview)

Текстовые блоки – не единственное обновление, предложенное в JEP 326 и запланированное для Java 12. Первая реализация необработанных строковых литералов была сырой и не продумана до мелочей.

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

String html ="<html>\n" +
			  "   <body>\n" +
			  "      <p>Hello, people!</p>\n" +
			  "   </body>\n" +
			  "</html>\n";

			  
 String json ="{\n" +
			  "   \"name\":\"proglib\",\n" +
			  "   \"age\":10\n" +
			  "}\n";

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

String html = """
                <html>
                    <body>
                        <p>Hello, people!</p>
                    </body>
                </html>
				""";

 String json = """
                {
                    "name":"proglib",
                    "age":10
                }
                """;

Если хочешь опробовать текстовые блоки на практике – подключи их явно для компиляции и выполнения:

javac --enable-preview --release 13 Example.java

java --enable-preview Example

Для получения более полной информации обратись в официальный хелп.

Как тебе новшества? Уже использовал что-то? Делитесь в комментариях.

Share

Тебе может это понравится...