インタフェースStableValue<T>

型パラメータ:
T - コンテンツのタイプ

パブリック・シール済インタフェースStableValue<T>
StableValueは、JavaプラットフォームのプレビューAPIです。
プレビュー機能が有効になっている場合のみ、プログラムでStableValueを使用できます。
プレビュー機能は、今後のリリースで削除するか、Javaプラットフォームの永続機能にアップグレードすることができます。
安定した値は、最大1回設定できる内容の保持者です。

StableValue<T>は通常、ファクトリ・メソッドStableValue.of()を使用して作成されます。 このように作成すると、安定した値は unsetになります。これは、contentsを保持しないことを意味します。 T型のコンテンツは、trySet()setOrThrow()またはorElseSet()をコールして設定できます。 一度設定すると、コンテンツは変更できず、orElseThrow()orElse()またはorElseSet()をコールして取得できます。

次の例を考えてみます。安定値フィールド"logger"は、Logger型の浅く不変なコンテンツ・ホルダーであり、最初にunsetとして作成され、コンテンツが保持されないことを意味します。 この例の後半で、「logger」フィールドの状態がチェックされ、まだ unsetである場合は、内容が setになります。

 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の複数のインスタンスが作成される場合があります。 ただし、コンテンツは、最初のライターが勝つことを意味する最大1回のみ設定できます。

Loggerのインスタンスが1つしか作成されないことを保証するために、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()をコールして、その内容を取得します。 安定値がunsetの場合、orElseSet()は指定されたサプライヤを評価し、結果にコンテンツを設定します。その結果はクライアントに返されます。 つまり、orElseSet()は、安定した値の内容が戻される前に設定されていることを保証します。

さらに、orElseSet()は、提供されている1つ以上のサプライヤのうち、最大で1つのサプライヤのみが評価され、logger.orElseSet()が同時に起動された場合でも1回のみ評価されることを保証します。 サプライヤの評価に副作用がある可能性があるため、このプロパティは重要です。たとえば、Logger.create()への前述のコールによってストレージ・リソースが準備される場合があります。

安定関数

安定した値は、より高いレベルの機能抽象化の基礎となります。 安定供給者は、値を計算し、その値をバッキング安定値ストレージにキャッシュしてその後に使用するための供給者です。 安定サプライヤは、StableValue.supplier()ファクトリを介して作成され、安定サプライヤへの初回アクセス時に起動される基礎となるサプライヤを提供します。
 public class Component {

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

     public void process() {
        logger.get().info("Process started");
        // ...
     }
 }
安定したサプライヤは、バッキングの安定した価値ストレージへのアクセスをカプセル化します。 つまり、Component内のコードは、getLogger()などのアクセッサ・メソッドを介さずに、安定サプライヤから直接ロガー・オブジェクトを取得できます。

stable int関数は、intパラメータを取得し、それを使用して、そのパラメータ値のバッキング安定値記憶域によってキャッシュされる結果を計算する関数です。 安定したIntFunctionは、StableValue.intFunction()ファクトリを介して作成されます。 作成時に、入力範囲([0, size))は、入力値ごとに最大1回起動される基礎となるIntFunctionとともに指定されます。 実際、stable 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()ファンクションは、基礎となるファンクションのUNDERLYING_POWER_OF_TWO入力範囲のサブセット[0, 5]のみを許可する部分ファンクションです。

安定関数は、パラメータ(T型)を取得し、それを使用して結果(R型)を計算し、そのパラメータ値のバッキング安定値記憶域によってキャッシュされる関数です。 安定した関数は、StableValue.function()ファクトリを介して作成されます。 作成時に、入力Setは、入力パラメータごとに最大1回起動される基礎となる関数とともに指定されます。 実際には、安定した関数は基礎となる関数のキャッシュのように動作します。

 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()ファンクションは、基礎となるファンクションのUNDERLYING_LOG2入力範囲のサブセット{1, 2, 4, 8, 16, 32}のみを許可する部分ファンクションです。

安定したコレクション

安定した値は、変更不可能なコレクションのバッキング・ストレージとしても使用できます。 安定リストは、安定した値の配列に裏付けられた変更不可能なリストです。 安定したリスト要素は、指定された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

同様に、安定マップは、構築時にキーが認識される変更不可能なマップです。 安定したマップ値は、指定された関数を使用して、最初にアクセスしたときに計算されます。

 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);
     }

 }
FIBFibonacci::fibの両方が相互に再帰します。 安定したint関数FIBは中間結果をキャッシュするため、従来の非キャッシュ再帰フィボナッチ法と比較して、初期計算の複雑さが指数関数から線形に減少します。 計算されると、VMはFibonacci.fib(5)のような定数倍式の自由になります。

前述のfibonacciの例は有向環状グラフです(つまり、循環依存関係がなく、したがって依存関係ツリーです)。


              ___________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をスローします。

スレッド安全性

安定した値の内容は、最大1回設定することが保証されます。 競合しているスレッドが安定した値を設定するために競合している場合、1つの更新のみが成功し、他の更新は安定した値が設定されるまでブロックされます。その後、他の更新では安定した値が設定され、安定した値は変更されません。

正常な読取り操作(orElseThrow()など)の前に成功する安定した値に対する書込み操作が1回以上実行されます(trySet()など)。 正常な書込み操作は次のいずれかです。

正常な読取り操作は次のいずれかです。

メソッドorElseSet(Supplier)は、指定されたサプライヤが競合中であっても、最大で1回正常に起動することを保証します。 orElseSet(Supplier)の呼出しは、ゼロ以上の例外的な呼出しの合計順序を形成し、その後にゼロ(コンテンツがすでに設定されている場合)または1回の正常な呼出しが続きます。 安定した関数と安定したコレクションは orElseSet()と同じ原則の上に構築されるため、スレッドも安全であり、入力ごとに1回以上起動することが保証されます。

パフォーマンス

安定した値の内容は、設定後に変更されることはないため、JVM実装は、安定した値を設定するために、その安定した値の将来のすべての読取りを取り除き、以前に観察した内容を直接使用する場合があります。 これは、安定値への参照が定数である場合(たとえば、安定値自体がstatic finalフィールドに格納されている場合)に当てはまります。 安定した関数およびコレクションは、StableValueの上に構築されます。 そのため、StableValueと同じJVM最適化の対象となる場合もあります。
実装要件:
StableValueのクラスの実装は、thisで自由に同期できるため、StableValueで(直接的または間接的に)同期しないようにする必要があります。 したがって、thisで同期するとデッドロックが発生する可能性があります。

StableValueの内容自体、orElse(other)パラメータおよびequals(obj)パラメータを除き、すべてのメソッド・パラメータがnull以外であるか、NullPointerExceptionがスローされます。

実装上のノート:
StableValueは、主にクラスの非公開フィールドであることを意図しており、通常、アクセッサを介して直接公開されることも、メソッド・パラメータとして渡されることもありません。

安定した関数およびコレクションは、呼び出されたときに内部安定値の評価をトリガーしないObject.toString()操作を提供するために合理的な努力をします。 安定したコレクションには、コール時に内部安定値の評価を最小限に抑えようとするObject.equals(Object)操作があります。

オブジェクトは安定した値で設定できますが、削除されないため、意図しないメモリー・リークのソースになる可能性があります。 安定した値の内容は強く到達可能です。 到達可能な安定した値は、安定した値自体が収集されるまで、設定された内容を保持することに注意してください。

(任意のランクの)配列型である型パラメータTを持つStableValueでは、JVMは配列参照を安定した値としてただし、そのコンポーネントではないとしてのみ処理できます。 代わりに、任意の深さの安定したリストを使用でき、安定したコンポーネントが提供されます。 より一般的には、安定した値は任意の深さの他の安定した値を保持することができ、それでも推移的な定数を提供する。

安定した値、関数、およびコレクションは Serializableではありません。

導入されたバージョン:
25
  • メソッドのサマリー

    修飾子と型
    メソッド
    説明
    boolean
    this == objの場合はtrue、それ以外の場合はfalseを返します。
    static <T,R> Function<T,R>
    function(Set<? extends T> inputs, Function<? super T, ? extends R> underlying)
    新しい安定した関数を返します。
    int
    thisオブジェクトのアイデンティティ・ハッシュ・コードを返します。
    static <R> IntFunction<R>
    intFunction(int size, IntFunction<? extends R> underlying)
    新しい安定したIntFunctionを返します。
    boolean
    内容が設定されている場合は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で新しい事前設定された安定値を返します。
    orElse(T other)
    設定されている場合はコンテンツを戻し、それ以外の場合は指定されたother値を戻します。
    orElseSet(Supplier<? extends T> supplier)
    内容を返します。設定を解除すると、最初に指定されたsupplierを使用して内容の計算および設定を試みます。
    設定されている場合はコンテンツを戻し、それ以外の場合は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の内容は1回のみ設定でき、このメソッドはtrueを1回のみ返します。

      このメソッドが戻ると、このStableValueの内容は常に設定されます。

      パラメータ:
      contents - 設定
      戻り値:
      このStableValueの内容が指定されたcontentsに設定されている場合はtrue、それ以外の場合は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は、例外をスローせずに完了した場合、最大1回起動することが保証されます。 このメソッドが別のサプライヤで複数回呼び出された場合、例外をスローせずに完了すると、そのうちの1つのみが起動されます。

      サプライヤが(未チェック)例外をスローすると、その例外は再スローされ、コンテンツは設定されません。 最も一般的な使用方法は、次のように、遅延計算値または記憶された結果として機能する新しいオブジェクトを作成することです。

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

      このメソッドが正常に戻ると、コンテンツは常に設定されます。

      指定されたsupplierは、supplierが例外をスローしないかぎり、複数のスレッドから呼び出された場合でも1回のみ起動されます。

      パラメータ:
      supplier - 以前に設定されていない場合、内容の計算に使用されます。
      戻り値:
      内容。設定を解除すると、最初に指定されたsupplierを使用して内容の計算および設定が試行されます。
      スロー:
      IllegalStateException - 指定されたsupplierが、この安定した値を再帰的に設定しようとした場合。
    • setOrThrow

      void setOrThrow(T contents)
      このStableValueの内容を指定されたcontentsに設定するか、すでに設定されている場合はIllegalStateExceptionをスローします。

      このメソッドが戻り(または例外をスロー)すると、コンテンツは常に設定されます。

      パラメータ:
      contents - 設定
      スロー:
      IllegalStateException - 内容がすでに設定されている場合
      IllegalStateException - orElseSet(Supplier)によって起動されたサプライヤが、このメソッドを直接または間接的にコールして、この安定した値を再帰的に設定しようとする場合。
    • equals

      boolean equals(Object obj)
      this == objの場合はtrue、それ以外の場合はfalseを返します。
      オーバーライド:
      equals、クラスObject
      パラメータ:
      obj - 等価性をチェックする場合
      戻り値:
      this == objの場合はtrue、それ以外の場合はfalse
      関連項目:
    • hashCode

      int hashCode()
      thisオブジェクトのアイデンティティ・ハッシュ・コードを返します。
      オーバーライド:
      hashCode、クラスObject
      戻り値:
      thisオブジェクトのアイデンティティ・ハッシュ・コード
      関連項目:
    • 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)
      新規安定仕入先を返します。

      返されたサプライヤは、返されたサプライヤのget()メソッドを介して最初にアクセスされたときに、提供されたunderlyingサプライヤの値を記録するキャッシュ・サプライヤです。

      指定されたunderlyingサプライヤは、マルチスレッド環境でも最大1回正常に起動することが保証されます。 値がすでに計算中である場合に、返されたサプライヤのget()メソッドを呼び出す競合スレッドは、値が計算されるか、または計算スレッドによって例外がスローされるまでブロックされます。 その後、競合するスレッドは、新しく計算された値(ある場合)を監視し、underlyingサプライヤを実行しません。

      指定されたunderlyingサプライヤが例外をスローすると、最初のコール元に再スローされ、コンテンツは記録されません。

      指定されたunderlyingサプライヤが戻されたサプライヤを再帰的にコールすると、IllegalStateExceptionがスローされます。

      型パラメータ:
      T - 返されたサプライヤから提供された結果のタイプ
      パラメータ:
      underlying - キャッシュされた値の計算に使用されるサプライヤ
      戻り値:
      新しい安定したサプライヤー
    • intFunction

      static <R> IntFunction<R> intFunction(int size, IntFunction<? extends R> underlying)
      新しい安定したIntFunctionを返します。

      戻される関数は、許可されるint入力ごとに、戻される関数のapply()メソッドを介して最初にアクセスされたときに、指定されたunderlying関数の値を記録するキャッシュ関数です。 戻されたファンクションが[0, size)の範囲内にない入力で呼び出されると、IllegalArgumentExceptionがスローされます。

      指定されたunderlying関数は、マルチスレッド環境でも、許可される入力ごとに最大1回正常に起動することが保証されます。 値がすでに計算中であるときに、返された関数の 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)
      新しい安定した関数を返します。

      戻される関数は、inputsの指定されたセットで許可される各入力について、戻される関数のapply()メソッドを介して最初にアクセスされたときに、指定されたunderlying関数の値を記録するキャッシュ関数です。 戻された関数がinputsにない入力で呼び出されると、IllegalArgumentExceptionがスローされます。

      指定されたunderlying関数は、マルチスレッド環境でも、許可される入力ごとに最大1回正常に起動することが保証されます。 値がすでに計算中であるときに、返された関数の apply()メソッドを呼び出す競合スレッドは、値が計算されるか、または計算スレッドによって例外がスローされるまでブロックされます。

      指定されたunderlying関数を呼び出すと例外がスローされ、最初の呼出し元に再スローされ、内容は記録されません。

      指定されたunderlying関数が、同じ入力に対して戻された関数を再帰的にコールすると、IllegalStateExceptionがスローされます。

      型パラメータ:
      T - 返されるファンクションへの入力のタイプ
      R - 返されるファンクションによって提供される結果のタイプ
      パラメータ:
      inputs - (NULL以外)許可される入力値のセット
      underlying - キャッシュされた値の計算に使用されるFunction
      戻り値:
      新しい安定した機能
      スロー:
      NullPointerException - 指定されたinputsセットにnull要素が含まれている場合。
    • list

      static <E> List<E> list(int size, IntFunction<? extends E> mapper)
      指定されたsizeを持つ新しい安定リストを返します。

      返されるリストは、指定されたsizeを含む変更できないリストです。 リストの要素は、最初にアクセスされたときに(たとえば、List::getを介して)提供されたmapperを介して計算されます。

      指定されたmapperファンクションは、マルチスレッド環境でも、リスト索引ごとに最大1回正常に起動することが保証されます。 計算中の要素にすでにアクセスしている競合スレッドは、要素が計算されるか、計算スレッドによって例外がスローされるまでブロックされます。

      指定された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関数は、マルチスレッド環境でも、キーごとに最大1回正常に起動することが保証されます。 すでに計算中の値にアクセスしている競合スレッドは、要素が計算されるか、または計算スレッドによって例外がスローされるまでブロックされます。

      指定されたmapper関数を呼び出すと例外がスローされ、初期コール元に再スローされ、指定されたキーに関連付けられた値は記録されません。

      返されるマップのMap.values()ビューまたはMap.entrySet()ビューも安定しています。

      返されるマップは変更できず、Mapインタフェースにオプションの操作を実装しません。

      指定されたmapperが、返されたマップを同じキーに対して再帰的にコールすると、IllegalStateExceptionがスローされます。

      型パラメータ:
      K - 返されるマップによって保持されるキーのタイプ
      V - 返されるマップ内のマップされた値のタイプ
      パラメータ:
      keys - 返されるマップ内の(null以外の)キー
      mapper - 関連付けられた値が最初にアクセスされるたびに起動します(nullを返す場合があります)
      戻り値:
      指定されたkeysの新しい安定したマップ
      スロー:
      NullPointerException - 指定されたinputsセットにnull要素が含まれている場合。