Привет, Хабр! В 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. Подробнее