Spec-Zone.ru › OpenJDK 25

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

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

StableValue<T> обычно создаётся с помощью фабричного метода StableValue.of(). При таком способе создания стабильное значение находится в состоянии не задано, то есть не содержит содержимого. Его содержимое типа T можно задать вызовом trySet(), setOrThrow() или orElseSet(). После задания содержимое больше не может измениться; получить его можно вызовом orElseThrow() , orElse() или orElseSet().

Рассмотрим следующий пример, в котором поле стабильного значения "logger" является поверхностно неизменяемым контейнером содержимого типа Logger и изначально создаётся в состоянии не задано, то есть не содержит содержимого. Далее в примере проверяется состояние поля "logger", и, если оно всё ещё находится в состоянии не задано, содержимое задаётся:

 public class Component {

    // Creates a new unset stable value with no contents
    private final StableValue<Logger> logger = StableValue.of();

    private Logger getLogger() {
        if (!logger.isSet()) {
            logger.trySet(Logger.create(Component.class));
        }
        return logger.orElseThrow();
    }

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

Если getLogger() вызывается из нескольких потоков, могут быть созданы несколько экземпляров Logger. Однако содержимое можно задать не более одного раза: побеждает первый записавший поток.

Чтобы гарантировать, что даже при гонках будет создан только один экземпляр Logger, вместо этого можно использовать метод orElseSet(). В этом случае содержимое вычисляется лениво и атомарно задаётся с помощью поставщика. В приведённом ниже примере поставщик задан в виде лямбда-выражения:

 public class Component {

    // Creates a new unset stable value with no contents
    private final StableValue<Logger> logger = StableValue.of();

    private Logger getLogger() {
        return logger.orElseSet( () -> Logger.create(Component.class) );
    }

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

Метод getLogger() вызывает logger.orElseSet() для получения содержимого стабильного значения. Если стабильное значение находится в состоянии не задано, orElseSet() вычисляет переданный поставщик и задаёт содержимое равным результату; затем результат возвращается вызывающему коду. Иными словами, orElseSet() гарантирует, что содержимое стабильного значения будет задано до возврата из метода.

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

Стабильные функции

Стабильные значения служат основой для функциональных абстракций более высокого уровня. Стабильный поставщик — это поставщик, который вычисляет значение, а затем кэширует его в базовом хранилище стабильного значения для последующего использования. Стабильный поставщик создаётся с помощью фабричного метода StableValue.supplier(), которому передаётся базовый Supplier; он вызывается при первом обращении к стабильному поставщику:
 public class Component {

     private final Supplier<Logger> logger =
             StableValue.supplier( () -> Logger.getLogger(Component.class) );

     public void process() {
        logger.get().info("Process started");
        // ...
     }
 }
Стабильный поставщик инкапсулирует доступ к своему базовому хранилищу стабильного значения. Это означает, что код внутри Component может получить объект logger непосредственно из стабильного поставщика, не прибегая к методу доступа, например getLogger().

Стабильная функция int — это функция, которая принимает параметр int и использует его для вычисления результата, который затем кэшируется в базовом хранилище стабильного значения для этого значения параметра. Стабильная IntFunction создаётся с помощью фабричного метода StableValue.intFunction(). При создании задаётся диапазон входных значений (то есть [0, size)), а также базовый IntFunction, который вызывается не более одного раза для каждого входного значения. По сути, стабильная функция int работает как кэш для базовой IntFunction:

 final class PowerOf2Util {

     private PowerOf2Util() {}

     private static final int SIZE = 6;
     private static final IntFunction<Integer> UNDERLYING_POWER_OF_TWO =
         v -> 1 << v;

     private static final IntFunction<Integer> POWER_OF_TWO =
         StableValue.intFunction(SIZE, UNDERLYING_POWER_OF_TWO);

     public static int powerOfTwo(int a) {
         return POWER_OF_TWO.apply(a);
     }
 }

 int result = PowerOf2Util.powerOfTwo(4);   // May eventually constant fold to 16 at runtime

Функция PowerOf2Util.powerOfTwo() является частичной функцией, которая допускает только подмножество [0, 5] входного диапазона UNDERLYING_POWER_OF_TWO базовой функции.

Стабильная функция — это функция, которая принимает параметр (типа T) и использует его для вычисления результата (типа R), который затем кэшируется в базовом хранилище стабильного значения для этого значения параметра. Стабильная функция создаётся с помощью фабричного метода StableValue.function(). При создании задаётся входной набор Set, а также базовая Function, которая вызывается не более одного раза для каждого входного значения. По сути, стабильная функция работает как кэш для базовой Function:

 class Log2Util {

     private Log2Util() {}

     private static final Set<Integer> KEYS =
         Set.of(1, 2, 4, 8, 16, 32);
     private static final UnaryOperator<Integer> UNDERLYING_LOG2 =
         i -> 31 - Integer.numberOfLeadingZeros(i);

     private static final Function<Integer, Integer> LOG2 =
         StableValue.function(KEYS, UNDERLYING_LOG2);

     public static int log2(int a) {
         return LOG2.apply(a);
     }

 }

 int result = Log2Util.log2(16);   // May eventually constant fold to 4 at runtime
Функция Log2Util.log2() является частичной функцией, которая допускает только подмножество {1, 2, 4, 8, 16, 32} входного диапазона UNDERLYING_LOG2 базовой функции.

Стабильные коллекции

Стабильные значения также можно использовать как базовое хранилище для неизменяемых коллекций. Стабильный список — это неизменяемый список, поддерживаемый массивом стабильных значений. Элементы стабильного списка вычисляются при первом обращении к ним с помощью переданной IntFunction:
final class PowerOf2Util {

    private PowerOf2Util() {}

    private static final int SIZE = 6;
    private static final IntFunction<Integer> UNDERLYING_POWER_OF_TWO =
            v -> 1 << v;

    private static final List<Integer> POWER_OF_TWO =
        StableValue.list(SIZE, UNDERLYING_POWER_OF_TWO);

    public static int powerOfTwo(int a) {
        return POWER_OF_TWO.get(a);
    }
}

int result = PowerOf2Util.powerOfTwo(4);   // May eventually constant fold to 16 at runtime

Аналогично, стабильная карта — это неизменяемая карта, ключи которой известны при создании. Значения стабильной карты вычисляются при первом обращении к ним с помощью переданной Function:

 class Log2Util {

     private Log2Util() {}

     private static final Set<Integer> KEYS =
         Set.of(1, 2, 4, 8, 16, 32);
     private static final UnaryOperator<Integer> UNDERLYING_LOG2 =
         i -> 31 - Integer.numberOfLeadingZeros(i);

     private static final Map<Integer, INTEGER> LOG2 =
         StableValue.map(CACHED_KEYS, UNDERLYING_LOG2);

     public static int log2(int a) {
          return LOG2.get(a);
     }

 }

 int result = Log2Util.log2(16);   // May eventually constant fold to 4 at runtime

Композиция стабильных значений

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

     private DependencyUtil() {}

     public static class Foo {
          // ...
      }

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

     private static final Supplier<Foo> FOO = StableValue.supplier(Foo::new);
     private static final Supplier<Bar> BAR = StableValue.supplier(() -> new Bar(FOO.get()));

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

     public static Bar bar() {
         return BAR.get();
     }

 }
Вызов bar() создаст единственный экземпляр Bar, если он ещё не создан. При его создании зависимый Foo будет предварительно создан, если Foo ещё не существует.

Ещё один пример, с более сложным графом зависимостей, — ленивое вычисление последовательности Фибоначчи:

 public final class Fibonacci {

     private Fibonacci() {}

     private static final int MAX_SIZE_INT = 46;

     private static final IntFunction<Integer> FIB =
         StableValue.intFunction(MAX_SIZE_INT, Fibonacci::fib);

     public static int fib(int n) {
         return n < 2
                 ? n
                 : FIB.apply(n - 1) + FIB.apply(n - 2);
     }

 }
И FIB, и Fibonacci::fib рекурсивно вызывают друг друга. Поскольку стабильная функция int FIB кэширует промежуточные результаты, начальная вычислительная сложность снижается с экспоненциальной до линейной по сравнению с традиционным рекурсивным методом вычисления чисел Фибоначчи без кэширования. После вычисления виртуальная машина может сворачивать в константы такие выражения, как Fibonacci.fib(5).

Приведённый выше пример с числами Фибоначчи представляет собой ориентированный ациклический граф (то есть не содержит циклических зависимостей и поэтому является деревом зависимостей):


              ___________fib(5)____________
             /                             \
       ____fib(4)____                  ____fib(3)____
      /              \                /              \
    fib(3)          fib(2)          fib(2)          fib(1)
   /     \         /     \         /     \
 fib(2) fib(1)   fib(1) fib(0)   fib(1) fib(0)
Если в графе зависимостей есть циклические зависимости, стабильное значение в конечном итоге выбросит исключение IllegalStateException при обращении к элементам, участвующим в цикле.

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

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

Успешная операция записи в стабильное значение, выполняемая не более одного раза (например, trySet()), происходит до любой успешной операции чтения (например, orElseThrow()). Успешной операцией записи может быть:

  • trySet(Object), возвращающий true;
  • setOrThrow(Object), не выбрасывающий исключение; или
  • orElseSet(Supplier), успешно выполняющий поставщик.
Успешной операцией чтения может быть:
  • orElseThrow(), не выбрасывающий исключение;
  • orElse(other), возвращающий значение, отличное от other;
  • orElseSet(Supplier), не вызывающий throw; или
  • isSet(), возвращающий true

Метод orElseSet(Supplier) гарантирует, что переданный Supplier будет успешно вызван не более одного раза даже при гонке. Вызовы orElseSet(Supplier) образуют полный порядок: ноль или более вызовов, завершившихся исключением, за которыми следует ноль (если содержимое уже было задано) или один успешный вызов. Поскольку стабильные функции и стабильные коллекции построены на тех же принципах, что и orElseSet(), они также являются потокобезопасными и гарантируют не более одного вызова для каждого входного значения.

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

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

За исключением самого содержимого StableValue, параметра orElse(other) и параметра equals(obj), все параметры методов должны быть не равны null, иначе будет выброшено исключение NullPointerException.

Примечание по реализации:
StableValue в основном предназначено для непубличного поля класса и обычно не предоставляется напрямую через методы доступа и не передаётся в качестве параметра метода.

Стабильные функции и коллекции стараются предоставлять операции Object.toString(), которые при вызове не запускают вычисление внутренних стабильных значений. Стабильные коллекции предоставляют операции Object.equals(Object), которые при вызове стараются свести к минимуму вычисление внутренних стабильных значений.

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

StableValue с параметром типа T, являющимся типом массива произвольной размерности, позволит JVM рассматривать как стабильное значение только ссылку на массив, но не его компоненты. Вместо этого можно использовать стабильный список произвольной глубины, который обеспечивает стабильность компонентов. В более общем случае стабильное значение может содержать другие стабильные значения произвольной глубины и при этом обеспечивать транзитивную неизменяемость.

Стабильные значения, функции и коллекции не являются Serializable.

С версии:
25

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

Модификатор и тип Метод Описание
boolean equals(Object obj)
Возвращает true, если this == obj, иначе false.
static <T,R> Function<T,R> function(Set<? extends T> inputs, Function<? super T, ? extends R> underlying)
Возвращает новую стабильную Function.
int hashCode()
Возвращает хеш-код идентичности объекта this.
static <R> IntFunction<R> intFunction(int size, IntFunction<? extends R> underlying)
Возвращает новую стабильную IntFunction.
boolean isSet()
Возвращает true, если содержимое задано, иначе false.
static <E> List<E> list(int size, IntFunction<? extends E> mapper)
Возвращает новый стабильный список с переданным size.
static <K,V> Map<K,V> map(Set<K> keys, Function<? super K, ? extends V> mapper)
Возвращает новую стабильную карту с переданным keys.
static <T> StableValuePREVIEW<T> of()
Возвращает новое незаданное стабильное значение.
static <T> StableValuePREVIEW<T> of(T contents)
Возвращает новое предварительно заданное стабильное значение с переданным contents.
T orElse(T other)
Возвращает содержимое, если оно задано; в противном случае возвращает переданное значение other.
T orElseSet(Supplier<? extends T> supplier)
Возвращает содержимое; если оно не задано, сначала пытается вычислить и задать его с помощью переданного supplier.
T orElseThrow()
Возвращает содержимое, если оно задано; в противном случае выбрасывает NoSuchElementException.
void setOrThrow(T contents)
Задаёт содержимое этого StableValue равным переданному contents или, если оно уже задано, выбрасывает IllegalStateException.
static <T> Supplier<T> supplier(Supplier<? extends T> underlying)
Возвращает нового стабильного поставщика.
boolean trySet(T contents)
Пытается задать содержимое этого StableValue равным переданному contents.

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

trySet

boolean trySet(T contents)
Пытается установить содержимое этого StableValue в предоставленное значение contents. Содержимое этого StableValue можно установить только один раз, поэтому этот метод возвращает true только один раз.

К моменту возврата этого метода содержимое этого StableValue всегда установлено.

Параметры:
contents — значение, которое нужно установить
Возвращает:
true, если содержимое этого StableValue было установлено в предоставленное значение contents, и false в противном случае
Вызывает:
IllegalStateException — если поставщик, вызванный методом orElseSet(Supplier), рекурсивно пытается установить это стабильное значение, прямо или косвенно вызывая данный метод.

orElse

T orElse(T other)
Возвращает содержимое, если оно установлено, а в противном случае возвращает предоставленное значение other.
Параметры:
other — значение, возвращаемое, если содержимое не установлено
Возвращает:
содержимое, если оно установлено, а в противном случае — предоставленное значение other

orElseThrow

T orElseThrow()
Возвращает содержимое, если оно установлено, а в противном случае выбрасывает NoSuchElementException.
Возвращает:
содержимое, если оно установлено, а в противном случае выбрасывает NoSuchElementException
Вызывает:
NoSuchElementException — если содержимое не установлено

isSet

boolean isSet()
Возвращает true, если содержимое установлено, и false в противном случае.
Возвращает:
true, если содержимое установлено, и false в противном случае

orElseSet

T orElseSet(Supplier<? extends T> supplier)
Возвращает содержимое; если оно не установлено, сначала пытается вычислить и установить его с помощью предоставленного поставщика supplier.

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

Если поставщик выбрасывает (непроверяемое) исключение, оно повторно выбрасывается, и содержимое не устанавливается. Чаще всего этот метод используется для создания нового объекта, служащего лениво вычисляемым значением или мемоизированным результатом, например:

Value v = stable.orElseSet(Value::new);

При успешном возврате этого метода содержимое всегда установлено.

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

Параметры:
supplier — поставщик, используемый для вычисления содержимого, если оно ещё не установлено
Возвращает:
содержимое; если оно не установлено, сначала предпринимается попытка вычислить и установить его с помощью предоставленного поставщика supplier
Вызывает:
IllegalStateException — если предоставленный supplier рекурсивно пытается установить это стабильное значение.

setOrThrow

void setOrThrow(T contents)
Устанавливает содержимое этого StableValue в предоставленное значение contents или, если оно уже установлено, выбрасывает IllegalStateException.

К моменту возврата этого метода (или выбрасывания исключения) содержимое всегда установлено.

Параметры:
contents — значение, которое нужно установить
Вызывает:
IllegalStateException — если содержимое уже было установлено
IllegalStateException — если поставщик, вызванный методом orElseSet(Supplier), рекурсивно пытается установить это стабильное значение, прямо или косвенно вызывая данный метод.

equals

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

hashCode

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

of

static <T> StableValuePREVIEW<T> of()
Возвращает новое неустановленное стабильное значение.

Неустановленное стабильное значение не имеет содержимого.

Параметры типа:
T — тип содержимого
Возвращает:
новое неустановленное стабильное значение

of

static <T> StableValuePREVIEW<T> of(T contents)
Возвращает новое предварительно установленное стабильное значение с предоставленным значением contents.
Параметры типа:
T — тип содержимого
Параметры:
contents — значение, которое нужно установить
Возвращает:
новое предварительно установленное стабильное значение с предоставленным значением contents

supplier

static <T> Supplier<T> supplier(Supplier<? extends T> underlying)
Возвращает нового стабильного поставщика.

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

Гарантируется, что предоставленный поставщик underlying будет успешно вызван не более одного раза даже в многопоточной среде. Потоки, конкурирующие за вызов метода get() возвращаемого поставщика, пока значение уже вычисляется, будут заблокированы до вычисления значения или выбрасывания исключения вычисляющим потоком. Затем конкурирующие потоки увидят вновь вычисленное значение (если оно есть) и больше никогда не будут выполнять поставщик underlying.

Если предоставленный поставщик underlying выбрасывает исключение, оно повторно выбрасывается исходному вызывающему коду, а содержимое не сохраняется.

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

Параметры типа:
T — тип результатов, предоставляемых возвращаемым поставщиком
Параметры:
underlying — поставщик, используемый для вычисления кэшированного значения
Возвращает:
нового стабильного поставщика

intFunction

static <R> IntFunction<R> intFunction(int size, IntFunction<? extends R> underlying)
Возвращает новую стабильную IntFunction.

Возвращаемая функция является кэшируемой функцией, которая для каждого допустимого входного значения int сохраняет значения предоставленной функции underlying при первом обращении к методу apply() возвращаемой функции. Если возвращаемая функция вызывается с входным значением, не входящим в диапазон [0, size), будет выброшено исключение IllegalArgumentException.

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

Если вызов предоставленной функции underlying выбрасывает исключение, оно повторно выбрасывается исходному вызывающему коду, а содержимое не сохраняется.

Если предоставленная функция underlying рекурсивно вызывает возвращаемую функцию с тем же входным значением, будет выброшено исключение IllegalStateException.

Параметры типа:
R — тип результатов, предоставляемых возвращаемой IntFunction
Параметры:
size — верхняя граница диапазона [0, size), определяющего допустимые входные значения
underlying — IntFunction, используемая для вычисления кэшированных значений
Возвращает:
новую стабильную IntFunction
Вызывает:
IllegalArgumentException — если предоставленное значение size отрицательно.

function

static <T,R> Function<T,R> function(Set<? extends T> inputs, Function<? super T, ? extends R> underlying)
Возвращает новую стабильную Function.

Возвращаемая функция является кэшируемой функцией, которая для каждого допустимого входного значения из заданного набора inputs сохраняет значения предоставленной функции underlying при первом обращении к методу apply() возвращаемой функции. Если возвращаемая функция вызывается с входным значением, отсутствующим в inputs, будет выброшено исключение IllegalArgumentException.

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

Если вызов предоставленной функции underlying выбрасывает исключение, оно повторно выбрасывается исходному вызывающему коду, а содержимое не сохраняется.

Если предоставленная функция underlying рекурсивно вызывает возвращаемую функцию с тем же входным значением, будет выброшено исключение IllegalStateException.

Параметры типа:
T — тип входных значений возвращаемой Function
R — тип результатов, предоставляемых возвращаемой Function
Параметры:
inputs — набор допустимых (ненулевых) входных значений
underlying — Function, используемая для вычисления кэшированных значений
Возвращает:
новую стабильную Function
Вызывает:
NullPointerException — если предоставленный набор inputs содержит элемент null.

list

static <E> List<E> list(int size, IntFunction<? extends E> mapper)
Возвращает новый стабильный список с предоставленным size.

Возвращаемый список является немодифицируемым списком с предоставленным size. Элементы списка вычисляются с помощью предоставленной функции mapper при первом обращении к ним (например, через List::get).

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

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

Представления возвращаемого списка subList и List.reversed() также являются стабильными.

Возвращаемый список и его представления subList или List.reversed() реализуют интерфейс RandomAccess.

Возвращаемый список является немодифицируемым и не реализует необязательные операции необязательные операции интерфейса List.

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

Параметры типа:
E — тип элементов возвращаемого списка
Параметры:
size — размер возвращаемого списка
mapper — функция, вызываемая при первом обращении к элементу (может возвращать null)
Возвращает:
новый стабильный список с предоставленным size
Вызывает:
IllegalArgumentException — если предоставленное значение size отрицательно.

map

static <K,V> Map<K,V> map(Set<K> keys, Function<? super K, ? extends V> mapper)
Возвращает новую стабильную карту с предоставленным keys.

Возвращаемая карта является немодифицируемой картой, ключи которой известны при создании. Значения карты вычисляются с помощью предоставленного mapper при первом обращении к ним (например, через Map::get).

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

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

Представления возвращаемой карты Map.values() и Map.entrySet() также являются стабильными.

Возвращаемая карта является немодифицируемой и не реализует необязательные операции необязательные операции интерфейса Map.

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

Параметры типа:
K — тип ключей, хранящихся в возвращаемой карте
V — тип отображаемых значений в возвращаемой карте
Параметры:
keys — (ненулевые) ключи возвращаемой карты
mapper — функция, вызываемая при первом обращении к связанному значению (может возвращать null)
Возвращает:
новую стабильную карту с предоставленным keys
Вызывает:
NullPointerException — если предоставленный набор inputs содержит элемент null.

Сообщить об ошибке или предложить улучшение
Дополнительную справочную информацию по API и документацию для разработчиков см. в документации Java SE, содержащей более подробные описания для разработчиков, обзоры концепций, определения терминов, обходные решения и работающие примеры кода. Другие версии.
Java является товарным знаком или зарегистрированным товарным знаком Oracle и/или ее дочерних компаний в США и других странах.
Авторское право © 1993, 2025, 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.
https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/StableValue.html

Spec-Zone.ru

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