インタフェースLazyConstant<T>
- 型パラメータ:
T- 定数の型
- すべてのスーパー・インタフェース:
Supplier<T>
LazyConstantは、JavaプラットフォームのプレビューAPIです。
遅延定数は、ファクトリ・メソッドLazyConstant.of(<computing function>)を使用して作成されます。
作成時、遅延定数は初期化されません。つまり、内容がありません。
遅延定数(T型)は、get()をコールして初期化(およびそのコンテンツが取得)できます。 get()が最初に呼び出されたときに、基になる computing function (構築時に提供)が呼び出され、その結果が定数の初期化に使用されます。
遅延定数を初期化すると、その内容は変更しないことができ、後続の 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()は、定数が返される前に initializedされることを保証し、例外を禁止します。
さらに、get()は、計算関数を同時に呼び出そうとする複数のスレッドのうち、計算のために1つだけが選択されることを保証します。 このプロパティは、コンピューティング関数の評価に副作用がある可能性があるため、重要です。たとえば、前述のLogger.create()をコールすると、ストレージ・リソースが準備される可能性があります。
例外処理
計算関数がnullを返す場合、NullPointerExceptionがスローされます。 したがって、遅延定数はnull値を保持できません。 null可能な定数を使用するクライアントは、値を「オプション」ホルダーにラップできます。
コンピューティング関数が(直接または間接的に遅延定数を介して)自身を再帰的に呼び出す場合、IllegalStateExceptionがスローされ、遅延定数は初期化されません。
遅延定数を構成しています
レイジー定数は、他のレイジー定数に依存し、レイジー計算が可能な依存関係グラフを形成しますが、個々の要素へのアクセスは引き続き実行可能です。 次の例では、単一のFooおよびBarインスタンス(Fooインスタンスに依存)がレイジーに作成され、どちらもレイジー定数によって保持されます。
public final class DependencyUtil {
private DependencyUtil() {}
public static class Foo {
// ...
}
public static class Bar {
public Bar(Foo foo) {
// ...
}
}
private static final LazyConstant<Foo> FOO = LazyConstant.of( Foo::new );
private 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が最初に作成されます。
スレッド安全性
遅延定数は、原子的にも最大で一度も初期化されることが保証されます。 競合するスレッドが遅延定数を初期化するために競合している場合、コンピューティング関数(呼び出し側のスレッド上で実行され、その後は計算スレッドと示される)を実行する更新スレッドは1つだけです。一方、他のスレッドは定数が初期化されるまでブロックされ、その後、他のスレッドは遅延定数が初期化され、定数は変更されず、計算は呼び出されません。
計算関数の呼び出しと、初期化された定数の内容のhappens-before定数の結果の初期化が読み取られます。 したがって、新しく作成されたオブジェクトのfinalフィールドを含め、初期化された定数のコンテンツは安全に公開されます。
スレッドの中断では、遅延定数の初期化は取り消されません。 つまり、計算スレッドが中断された場合、LazyConstant::getは中断されたスレッドのステータスをクリアせず、InterruptedExceptionもスローしません。
計算関数が無期限にブロックされた場合、この遅延定数で動作しているほかのスレッドは無期限にブロックされる可能性があり、タイムアウトやキャンセルは提供されません。
パフォーマンス
遅延定数の内容は、遅延定数の初期化後に変更することはできません。 したがって、JVM実装では、初期化された遅延定数に対して、その遅延定数の内容の将来のすべての読取りを消去し、そのかわりに以前に観測された内容を使用できます。 この最適化を定数折りたたみと呼びます。 これは、static finalフィールドから遅延定数への直接参照がある場合、またはstatic finalフィールドからチェーンがある場合(1つ以上の信頼できるフィールド(つまり、static finalフィールド、レコード・フィールドまたは非表示クラスの最後のインスタンス・フィールド)から遅延定数への直接参照がある場合にのみ可能です。
雑
equals(obj)およびorElse(other)パラメータを除き、すべてのメソッド・パラメータはnull以外にする必要があり、そうでない場合はNullPointerExceptionがスローされます。- APIのノート:
- 一度遅延定数を初期化すると、その内容は削除できなくなります。 これは、意図しないメモリー・リークの原因になる可能性があります。 より具体的には、遅延定数がその内容を強く参照します。 したがって、遅延定数自体に到達できるかぎり、遅延定数の内容に到達できます。
配列を遅延定数内に格納することは可能ですが、それによって配列要素のアクセス・パフォーマンスが向上することはありません。 かわりに、任意の深さの遅延リストPREVIEWを使用できます。これにより、定数コンポーネントが提供されます。
LazyConstant型はSerializableではありません。静的イニシャライザで使用すると、クラスの初期化順序と相互作用する可能性があります。循環初期化では、Java言語仕様の12.4の項で説明されているように、初期化エラーが発生する可能性があります。
- 実装上のノート:
- 遅延定数は、それ自体で自由に同期できます。 したがって、遅延定数で直接的または間接的に同期する場合は注意が必要です。 遅延定数は変更不可ですが、その内容は不変である場合とそうでない場合があります(たとえば、ArrayListを保持する場合があります)。
- Java言語仕様を参照してください:
-
12.4クラスおよびインタフェースの初期化
17.4.5事前の順序 - 導入されたバージョン:
- 26
- 関連項目:
-
メソッドのサマリー
修飾子と型メソッド説明booleanこの遅延定数が指定されたobjと同じインスタンスである場合、trueを返します。それ以外の場合はfalseを返します。get()この初期化された定数の内容を返します。 初期化されていない場合は、まず計算関数を使用してこの定数を計算および初期化します。inthashCode()この遅延定数のアイデンティティ・ハッシュ・コードを返します。boolean定数を初期化する場合はtrue、初期化しない場合はfalseを返します。static <T> LazyConstantPREVIEW<T> 指定されたcomputingFunctionを介してコンテンツを後で計算する遅延定数を返します。初期化されている場合はこの遅延定数の内容を戻し、それ以外の場合はotherを戻します。toString()デバッグに適した文字列を返します。
-
メソッドの詳細
-
orElse
-
get
-
isInitialized
boolean isInitialized()定数を初期化する場合はtrue、初期化しない場合はfalseを返します。このメソッドは、この遅延定数の初期化をトリガーすることはなく、ほかのスレッドによって原子的に行われた初期化状態の変更を観察します。
- 戻り値:
- 定数を初期化する場合は
true、それ以外の場合はfalse
-
equals
boolean equals(Object obj) この遅延定数が指定されたobjと同じインスタンスである場合、trueを返します。それ以外の場合はfalseを返します。つまり、equalsは、この遅延定数と
objのアイデンティティを比較して等価性を判断します。 したがって、同じ内容の2つの異なる遅延定数は等しくありません。このメソッドは、この遅延定数の初期化をトリガーしません。
-
hashCode
int hashCode()この遅延定数のアイデンティティ・ハッシュ・コードを返します。 このメソッドは、この遅延定数の初期化をトリガーしません。- オーバーライド:
hashCode、クラスObject- 戻り値:
- この遅延定数のアイデンティティ・ハッシュ・コード
- 関連項目:
-
toString
String toString()デバッグに適した文字列を返します。このメソッドは、この遅延定数の初期化をトリガーすることはなく、ほかのスレッドによる初期化を原子的に観察します(つまり、初期化がすでに完了している場合にのみ内容を観察します)。
この遅延定数を初期化すると、内容の Object.toString()を含む実装依存の文字列が返されます。それ以外の場合は、この遅延定数がまだ初期化されていないことを示す実装依存の文字列が返されます。
-
of
static <T> LazyConstantPREVIEW<T> of(Supplier<? extends T> computingFunction) 指定されたcomputingFunctionを介してコンテンツを後で計算する遅延定数を返します。戻された遅延定数は、少なくとも初期化が正常に完了するまで、指定された
computingFunctionを強く参照します。指定されたコンピューティング関数がすでに
LazyConstantのインスタンスである場合、そのメソッドは指定されたコンピューティング関数を直接返すことができます。- 実装上のノート:
- 初期化が正常に完了すると、計算機能は強く参照されなくなり、ガベージ・コレクションの対象になります。
- 型パラメータ:
T- 定数の型- パラメータ:
computingFunction- 定数の初期化に使用されるサプライヤの形式- 戻り値:
- 指定された
computingFunctionを介してコンテンツを後で計算する遅延定数
-
LazyConstantを使用できるのは、プレビュー機能が有効な場合のみです。