Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Lazy Constant - finalフィールドの遅延初期化

Lazy Constant - finalフィールドの遅延初期化

2025.11.15 JJUG CCC 2025 Fall 発表資料

Avatar for Yuichi.Sakuraba

Yuichi.Sakuraba

November 14, 2025
Tweet

More Decks by Yuichi.Sakuraba

Other Decks in Technology

Transcript

  1. フィールドの初期化 宣言時 final String text = ”Hello”; イニシャライザー final String

    text; { text = ”Hello”; } コンストラクタ final String text; Foo() { text = ”Hello”; } これ以外で代入するとコンパイルエラー
  2. class Consumer { final LazyConstant<Heavy> heavyConstant = LazyConstant.of(() -> new

    Heavy()); void consume() { Heavy heavy = heavyConstant.get(); ...... } ...... } で値の生成 初回コール時に を実行 回目からは単に値を返す
  3. で値の生成 初回コール時に を実行 回目からは単に値を返す class Consumer { final LazyConstant<Heavy> heavyConstant

    = LazyConstant.of(Heavy::new); void consume() { Heavy heavy = heavyConstant.get(); ...... } ...... }
  4. アイデアは と同じ class Singleton { static Singleton instance; private Singleton()

    { ... } Singleton get() { if (instance == null) { instance = new Singleton(); } return instance; } ...... }
  5. アイデアは と同じ class Singleton { static Singleton instance; private Singleton()

    { ... } synchronized Singleton get() { if (instance == null) { instance = new Singleton(); } return instance; } ...... } しかし、スケールしない
  6. アイデアは と同じ class Singleton { static volatile Singleton instance; private

    Singleton() { ... } Singleton get() { if (instance == null) { synchronized (this) { if (instance == null) { instance = new Singleton(); } } } return instance; }
  7. public final class LazyConstantImpl<T> implements LazyConstant<T> { @Stable private T

    constant; @ForceInline @Override public T get() { final T t = getAcquire(); return (t != null) ? t : getSlowPath(); } public final class LazyConstantImpl<T> implements LazyConstant<T> { @Stable private T constant; @ForceInline @Override public T get() { final T t = getAcquire(); return (t != null) ? t : getSlowPath(); }
  8. private T getSlowPath() { preventReentry(); synchronized (this) { T t

    = getAcquire(); if (t == null) { t = computingFunction.get(); Objects.requireNonNull(t); setRelease(t); // Allow the underlying supplier to be collected after successful use computingFunction = null; } return t; } } private T getSlowPath() { preventReentry(); synchronized (this) { T t = getAcquire(); if (t == null) { t = computingFunction.get(); Objects.requireNonNull(t); setRelease(t); // Allow the underlying supplier to be collected after successful use computingFunction = null; } return t; } }
  9. private T getSlowPath() { preventReentry(); synchronized (this) { T t

    = getAcquire(); if (t == null) { t = computingFunction.get(); Objects.requireNonNull(t); setRelease(t); // Allow the underlying supplier to be collected after successful use computingFunction = null; } return t; } } の実行
  10. スーパークラスのコンストラクターは サブクラスのコンストラクターの先頭 class B extends A { B() { super();

    // その他の処理 } } からコンストラクターのどこでも class B extends A { B() { // フィールドの初期化 super(); // その他の処理 } } ただし は使用不可 インスタンスメソッド使用不可 フィールドの参照は使用不可 などの制約あり
  11. class A { ... } class B extends A {

    ... } new B(); B() A() Object() A フィールド 初期化 B フィールド 初期化 この時点まで のフィールド未初期化 かつアクセス可能
  12. class A { ... } class B extends A {

    ... } A() フィールド 初期化 B() フィールド 初期化 new B(); Object() A 残処理 B 残処理 で対応済み