Spec-Zone.ru › OpenJDK 27

Интерфейс LazyConstant<T>

Параметры типа:
T - тип константы
Все суперинтерфейсы:
Supplier<T>
public sealed interface LazyConstant<T> extends Supplier<T>
LazyConstant — это API предварительного просмотра платформы Java.
Программы могут использовать LazyConstant только при включённых функциях предварительного просмотра.
Функции предварительного просмотра могут быть удалены в будущем выпуске или стать постоянными функциями платформы Java.
Ленивая константа — это контейнер содержимого, которое можно инициализировать не более одного раза.

Ленивая константа создаётся с помощью фабричного метода LazyConstant.of(<computing function>).

После создания ленивая константа не инициализирована, то есть не содержит данных.

Затем ленивую константу (типа T) можно инициализировать (и получить её содержимое), вызвав get(). При первом вызове get() вызывается базовая вычисляющая функция (переданная при создании), а её результат используется для инициализации константы.

После инициализации ленивой константы её содержимое никогда не меняется и всегда возвращается при последующих вызовах get().

Рассмотрим следующий пример, в котором поле ленивой константы "logger" содержит объект типа Logger:

public class Component {

   // Creates a new uninitialized lazy constant
   private final LazyConstant<Logger> logger =
           LazyConstant.of( () -> Logger.create(Component.class) );

   public void process() {
       logger.get().info("Process started");
       // ...
   }
}

Изначально ленивая константа не инициализирована. При первом вызове logger.get() вычисляется функция инициализации, а константа инициализируется полученным результатом; затем результат возвращается вызывающему коду. Таким образом, get() гарантирует, что константа будет инициализирована до возврата из метода, если не возникнет исключение.

Кроме того, get() гарантирует, что из нескольких потоков, одновременно пытающихся вызвать вычисляющую функцию, для вычисления всегда будет выбран только один. Это свойство крайне важно, поскольку вычисление функции может иметь побочные эффекты. Например, приведённый выше вызов Logger.create() может привести к подготовке ресурсов хранилища.

Обработка исключений

Если при вычислении вычисляющей функции возникает непроверяемое исключение (то есть исключение времени выполнения или ошибка), ленивая константа не инициализируется, а переходит в состояние ошибки, после чего выбрасывается NoSuchElementException, причиной которого является это непроверяемое исключение. Последующие вызовы get() выбрасывают NoSuchElementException без причины и с сообщением, содержащим имя класса исходного непроверяемого исключения; вычисляющая функция при этом больше не вызывается.

Все сбои обрабатываются таким образом. Существуют два особых случая, в которых выбрасываются непроверяемые исключения:

Если вычисляющая функция возвращает null, будет выброшено исключение NoSuchElementException (причиной которого является NullPointerException). Поэтому ленивая константа никогда не может содержать значение null. Клиенты, которым нужна константа, допускающая значение null, могут обернуть значение в контейнер Optional.

Если вычисляющая функция рекурсивно вызывает саму себя через ленивую константу, будет выброшено исключение NoSuchElementException (причиной которого является IllegalStateException).

Композиция ленивых констант

Ленивая константа может зависеть от других ленивых констант, образуя граф зависимостей, который можно вычислять лениво, сохраняя при этом высокую производительность доступа к отдельным элементам. В следующем примере лениво создаются один экземпляр Foo и один экземпляр Bar (зависящий от экземпляра Foo); оба хранятся в ленивых константах:
public static class Foo {
     // ...
 }

public static class Bar {
    public Bar(Foo foo) {
         // ...
    }
}

static final LazyConstant<Foo> FOO = LazyConstant.of( Foo::new );
static final LazyConstant<Bar> BAR = LazyConstant.of( () -> new Bar(FOO.get()) );

public static Foo foo() {
    return FOO.get();
}

public static Bar bar() {
    return BAR.get();
}
Вызов BAR.get() создаст синглтон Bar, если он ещё не создан. При таком создании сначала будет создан зависимый Foo, если Foo ещё не существует.

Потокобезопасность

Гарантируется, что ленивая константа инициализируется атомарно и не более одного раза. Если несколько конкурирующих потоков пытаются инициализировать ленивую константу, только один поток, выполняющий обновление, запускает вычисляющую функцию (она выполняется в потоке вызывающего кода и далее называется вычисляющим потоком), тогда как остальные потоки блокируются до инициализации константы (или сбоя вычисления). После этого остальные потоки видят, что ленивая константа инициализирована (или перешла в состояние ошибки), оставляют её без изменений и больше никогда не запускают вычисления.

Вызов вычисляющей функции и последующая инициализация константы происходят до чтения содержимого инициализированной константы. Таким образом, содержимое инициализированной константы, включая любые поля final вновь созданных объектов, безопасно публикуется. Поскольку последующие обращения к содержимому могут быть устранены, повторный вызов get() не обеспечивает никаких иных гарантий упорядочивания операций с памятью или видимости.

Прерывание потока не отменяет инициализацию ленивой константы. Иными словами, если вычисляющий поток прерван, LazyConstant::get не сбрасывает статус прерывания потока и не выбрасывает InterruptedException.

Если вычисляющая функция блокируется на неопределённое время, другие потоки, работающие с этой ленивой константой, также могут блокироваться на неопределённое время; тайм-ауты и отмена не предусмотрены.

Производительность

Содержимое ленивой константы не может измениться после её инициализации. Поэтому реализация JVM может для инициализированной ленивой константы устранить все последующие чтения её содержимого и использовать вместо них ранее полученное значение. Эта оптимизация называется свёрткой констант. Она возможна только при наличии прямой ссылки из поля static final на ленивую константу либо цепочки от поля static final к ленивой константе через одно или несколько доверенных полей (то есть полей static final, полей record или финальных нестатических полей в скрытых классах).
Примечание API:
После инициализации ленивой константы её содержимое нельзя удалить. Это может привести к непреднамеренной утечке памяти. В частности, ленивая константа сильно ссылается на своё содержимое. Поэтому содержимое ленивой константы остаётся доступным, пока доступна сама ленивая константа.

Хотя внутри ленивой константы можно хранить массив, это не повысит производительность доступа к элементам массива. Вместо этого можно использовать ленивый списокПРЕДВАРИТЕЛЬНЫЙ ПРОСМОТР произвольной глубины, предоставляющий постоянные компоненты.

Тип LazyConstant не реализует интерфейс Serializable.

Использование в статических инициализаторах может влиять на порядок инициализации классов; циклическая инициализация может привести к ошибкам инициализации, как описано в разделе §12.4 документа Спецификация языка Java.

Примечание по реализации:
Ленивая константа может синхронизироваться сама на себе. Поэтому необходимо соблюдать осторожность при прямой или косвенной синхронизации на ленивой константе. Ленивую константу нельзя изменить, но её содержимое может быть как изменяемым, так и неизменяемым (например, она может содержать ArrayList).
См. Спецификацию языка Java:
12.4 Инициализация классов и интерфейсов
17.4.5 Порядок «происходит до»
Начиная с:
26
См. также:
  • Optional
  • Supplier
  • List.ofLazy(int, IntFunction)ПРЕДВАРИТЕЛЬНЫЙ ПРОСМОТР
  • Map.ofLazy(Set, Function)ПРЕДВАРИТЕЛЬНЫЙ ПРОСМОТР

Краткое описание методов

Модификатор и тип Метод Описание
boolean equals(Object obj)
Возвращает true, если эта ленивая константа является тем же экземпляром, что и переданный obj; в противном случае возвращает false.
T get()
Возвращает инициализированное содержимое этой константы, вычисляя его при необходимости.
int hashCode()
Возвращает идентификационный хеш-код этой ленивой константы.
static <T> LazyConstantPREVIEW<T> of(Supplier<? extends T> computingFunction)
Возвращает новую ленивую константу, содержимое которой будет вычислено позднее с помощью переданного computingFunction.
String toString()
Возвращает строку, подходящую для отладки.

Подробное описание методов

get

T get()
Возвращает инициализированное содержимое этой константы, вычисляя его при необходимости.

Если эта константа не инициализирована, сначала вычисляет и инициализирует её с помощью вычисляющей функции.

После успешного возврата из этого метода гарантируется, что константа инициализирована.

Если при вычислении вычисляющей функции выбрасывается непроверяемое исключение или если вычисляющая функция возвращает null, эта ленивая константа не инициализируется, а переходит в состояние ошибки, после чего выбрасывается NoSuchElementException, как описано в разделе Обработка исключений.

Определён в:
get в интерфейсе Supplier<T>
Возвращает:
инициализированное содержимое этой константы, вычисленное при необходимости
Выбрасывает:
NoSuchElementException — если эта ленивая константа находится в состоянии ошибки

equals

boolean equals(Object obj)
Возвращает true, если эта ленивая константа является тем же экземпляром, что и переданный obj; в противном случае возвращает false.

Иными словами, equals сравнивает идентичность этой ленивой константы и obj, чтобы определить равенство. Поэтому две разные ленивые константы с одинаковым содержимым не равны.

Этот метод никогда не запускает инициализацию этой ленивой константы.

Переопределяет:
equals в классе Object
Параметры:
obj — объект-ссылка, с которым выполняется сравнение.
Возвращает:
true, если эта ленивая константа является тем же экземпляром, что и переданный obj; в противном случае возвращает false
См. также:
  • Object.hashCode()
  • HashMap

hashCode

int hashCode()
Возвращает идентификационный хеш-код этой ленивой константы. Этот метод никогда не запускает инициализацию этой ленивой константы.
Переопределяет:
hashCode в классе Object
Возвращает:
идентификационный хеш-код этой ленивой константы
См. также:
  • Object.equals(java.lang.Object)
  • System.identityHashCode(Object)

toString

String toString()
Возвращает строку, подходящую для отладки.

Этот метод никогда не запускает инициализацию этой ленивой константы и атомарно наблюдает за инициализацией, выполняемой другими потоками (то есть видит содержимое, только если инициализация уже завершилась).

Если эта ленивая константа инициализирована, возвращается зависящая от реализации строка, содержащая результат вызова Object.toString() для содержимого; в противном случае возвращается зависящая от реализации строка, указывающая, что эта ленивая константа ещё не инициализирована.

Переопределяет:
toString в классе Object
Возвращает:
строку, подходящую для отладки

of

static <T> LazyConstantPREVIEW<T> of(Supplier<? extends T> computingFunction)
Возвращает новую ленивую константу, содержимое которой будет вычислено позднее с помощью переданного computingFunction.

Возвращённая ленивая константа сохраняет сильную ссылку на переданный computingFunction до завершения вычисления (успешного или завершившегося ошибкой).

По замыслу метод всегда возвращает новую ленивую константу, даже если переданная вычисляющая функция уже является экземпляром LazyConstant. Клиенты, которые хотят избежать создания нового экземпляра в этом случае, могут написать вспомогательный метод, подобный показанному в приведённом ниже фрагменте, и создавать ленивые константы с его помощью вместо прямого вызова встроенного фабричного метода of(Supplier):

static <T> LazyConstant<T> ofFlattened(Supplier<? extends T> computingFunction) {
    return (computingFunction instanceof LazyConstant<? extends T> lc)
            ? (LazyConstant<T>) lc // unchecked cast is safe under normal generic usage
            : LazyConstant.of(computingFunction);
    }
Примечание по реализации:
после завершения вычисляющей функции (независимо от того, завершилась ли она успешно или выбросила непроверяемое исключение) сильная ссылка на неё больше не сохраняется, и она становится доступной для сборки мусора.
Параметры типа:
T — тип константы
Параметры:
computingFunction — в виде Supplier, используемого для инициализации константы
Возвращает:
новую ленивую константу, содержимое которой будет вычислено позднее с помощью переданного computingFunction
Выбрасывает:
NullPointerException — если переданный computingFunction является null

Сообщить об ошибке или предложить улучшение
Дополнительные справочные материалы по API и документацию для разработчиков см. в документации Java SE, содержащей более подробные описания для разработчиков, обзоры концепций, определения терминов, обходные решения и примеры работающего кода. Другие версии.
Java является товарным знаком или зарегистрированным товарным знаком Oracle и/или её дочерних компаний в США и других странах.
Авторские права © 1993, 2026, Oracle и/или её дочерние компании, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
Все права защищены. Использование регулируется условиями лицензии и политикой распространения документации.

© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API