5 фич в JDK, о которых вы могли не слышать

b7188c75a01cf0841aa5f009b58c7b03.png

Привет, Хабр! В JDK постоянно появляются новые возможности, но далеко не все из них получают заслуженное внимание. В этой статье я расскажу о пяти фичах JDK, о которых вы, возможно, не слышали.

А именно:

  • VarHandle API

  • Foreign Linker API

  • JEP 376: Скрытые классы

  • JEP 389: Foreign Function & Memory API

  • JEP 411: Депрекация Security Manager для удаления

VarHandle API

VarHandle — это альтернатива традиционным методам работы с полями и массивами, предоставляющая гибкий и производительный способ доступа к переменным.

VarHandle упрощает создание высокопроизводительных многопоточных приложений, имея атомарные операции и возможность работы с различными типами памяти.

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;

public class VarHandleDemo {
    private volatile int counter = 0;
    private static final VarHandle COUNTER_HANDLE;

    static {
        try {
            // Получаем VarHandle для поля 'counter' класса VarHandleDemo
            COUNTER_HANDLE = MethodHandles.lookup().findVarHandle(VarHandleDemo.class, "counter", int.class);
        } catch (ReflectiveOperationException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    // Метод для атомарного увеличения значения счетчика
    public void increment() {
        COUNTER_HANDLE.getAndAdd(this, 1);
    }

    // Метод для получения текущего значения счетчика
    public int getCounter() {
        return (int) COUNTER_HANDLE.get(this);
    }

    public static void main(String[] args) {
        VarHandleDemo demo = new VarHandleDemo();
        demo.increment();
        demo.increment();
        System.out.println("Counter: " + demo.getCounter()); // Вывод: Counter: 2
    }
}

Foreign Linker API

Foreign Linker API — хороший способ взаимодействия Java-приложений с нативными библиотеками, который заменил устаревший JNI.

import jdk.incubator.foreign.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;

public class ForeignLinkerDemo {
    public static void main(String[] args) throws Throwable {
        // Загружаем нативную библиотеку 'mathlib'
        System.loadLibrary("mathlib");

        // Получаем доступ к символам загруженной библиотеки
        SymbolLookup lookup = SymbolLookup.loaderLookup();

        // Ищем адрес функции 'add' в библиотеке
        MemoryAddress funcAddr = lookup.lookup("add")
                                      .orElseThrow(() -> new RuntimeException("Function not found"))
                                      .address();

        // Определяем сигнатуру метода: int add(int, int)
        MethodType mt = MethodType.methodType(int.class, int.class, int.class);

        // Создаем MethodHandle для вызова нативной функции
        MethodHandle mh = CLinker.getInstance().downcallHandle(
            funcAddr,
            mt,
            FunctionDescriptor.of(CLinker.C_INT, CLinker.C_INT, CLinker.C_INT)
        );

        // Вызываем нативную функцию и выводим результат
        int result = (int) mh.invokeExact(5, 7);
        System.out.println("Результат сложения: " + result); // Вывод: Результат сложения: 12
    }
}

JEP 376: Hidden Classes

Hidden Classes — это классы, которые не могут быть использованы напрямую приложениями или сторонними библиотеками. Они предназначены для динамической генерации и использования внутри JVM.

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;

public class HiddenClassDemo {
    public static void main(String[] args) throws Throwable {
        // Получаем экземпляр Lookup для текущего класса
        MethodHandles.Lookup lookup = MethodHandles.lookup();

        // Код скрытого класса в виде строки
        String classCode = """
            package secret;
            public class Hidden {
                public void greet() {
                    System.out.println("Привет из скрытого класса!");
                }
            }
            """;

        // Определяем скрытый класс внутри JVM
        Class hiddenClass = lookup.defineHiddenClass(
            classCode.getBytes(),
            false,
            MethodHandles.Lookup.ClassOption.NESTMATE
        ).lookupClass();

        // Создаем экземпляр скрытого класса
        Object instance = hiddenClass.getDeclaredConstructor().newInstance();

        // Получаем метод 'greet' и вызываем его
        Method greetMethod = hiddenClass.getMethod("greet");
        greetMethod.invoke(instance); // Вывод: Привет из скрытого класса!
    }
}

JEP 389: Foreign Function & Memory API

Foreign Function & Memory API дает способ работы с внешними функциями и управлением памятью вне JVM. Это альтернатива JNI.

import jdk.incubator.foreign.*;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.SymbolLookup;

public class ForeignFunctionMemoryDemo {
    public static void main(String[] args) throws Throwable {
        // Загружаем нативную библиотеку 'nativeLib'
        System.loadLibrary("nativeLib");

        // Получаем доступ к символам загруженной библиотеки
        SymbolLookup lookup = SymbolLookup.loaderLookup();

        // Ищем адрес функции 'multiply' в библиотеке
        MemoryAddress funcAddr = lookup.lookup("multiply")
                                      .orElseThrow(() -> new RuntimeException("Function not found"))
                                      .address();

        // Определяем сигнатуру метода: int multiply(int, int)
        MethodType mt = MethodType.methodType(int.class, int.class, int.class);
        FunctionDescriptor fd = FunctionDescriptor.of(CLinker.C_INT, CLinker.C_INT, CLinker.C_INT);

        // Создаем MethodHandle для вызова нативной функции
        var handle = CLinker.getInstance().downcallHandle(funcAddr, fd);

        // Вызываем нативную функцию и выводим результат
        int result = (int) handle.invokeExact(6, 7);
        System.out.println("Результат умножения: " + result); // Вывод: Результат умножения: 42
    }
}

JEP 411: Deprecate the Security Manager for Removal

JEP 411 объявляет о депрекации Security Manager и связанных с ним API, планируя их полное удаление в будущих версиях JDK.

public class SecurityManagerDemo {
    public static void main(String[] args) {
        // Устанавливаем Security Manager (до депрекации)
        System.setSecurityManager(new SecurityManager());

        try {
            // Пытаемся прочитать системное свойство 'user.home'
            String userHome = System.getProperty("user.home");
            System.out.println("User Home: " + userHome);
        } catch (SecurityException e) {
            // Если доступ запрещен, выводим сообщение
            System.out.println("Доступ запрещен!");
        }
    }
}

Заключение

А какие скрытые фичи JDK вы уже используете или планируете попробовать? Делитесь своими находками в комментариях ниже!

Всех желающих повысить свой уровень программирования на Java приглашаем на открытые уроки, которые скоро пройдут в рамках курса «Java Developer. Advanced»:

  • 12 ноября: Введение в GraalVM: ускоряем ваши Java-приложения. Подробнее

  • 21 ноября: Знакомство с виртуальными потоками Java. Подробнее

© Habrahabr.ru