Hi David,

Thank you for trying out LazyConstant and providing feedback. That is precisely 
what previews are for!

If you take a closer look at the specification of LazyConstant::orElse, it says 
that the method will never trigger initialization. And so, you can actually be 
sure that in your first example, foo is always initialized to "hello" (if ever 
initialized). It is only if foo is not initialized that the method will return 
"hello2" (again, without initializing foo). This is similar to how Optional 
works.

It would be possible to entirely remove the orElse() method from the API, and 
in the rare cases where an equivalent functionality is called for, rely on 
LazyConstant::isInitialized instead.

Best, Per


Confidential- Oracle Internal
________________________________
From: amber-dev <[email protected]> on behalf of david Grajales 
<[email protected]>
Sent: Friday, December 5, 2025 5:38 AM
To: amber-dev <[email protected]>; [email protected] 
<[email protected]>
Subject: Feedback about LazyConstants API (JEP526)

Dear Java Dev Team,

 I am writing to provide feedback and two specific observations regarding the 
LazyConstant API, which is currently a preview feature in OpenJDK 26.

 I appreciate the API's direction and I think it's a good improvement compared 
to its first iteration; however, I see potential for improved expressiveness, 
particularly in conditional scenarios.


1. Proposal: Zero-Parameter `LazyConstant.of()` Overload:

Currently, the mandatory use of a factory method receiving a `Supplier` (due to 
the lack of a public constructor) can obscure the expressiveness of conditional 
or multiple-value initialization paths. **The Issue:** When looking at the 
declaration:

LazyConstant<String> foo = LazyConstant.of(() -> "hello");

the code gives the strong, immediate impression that the value is always 
initialized to "hello". This makes it difficult to infer that the constant 
might ultimately resolve to an alternative value set later via orElse() or 
another conditional path, especially when skimming the code:

LazyConstant<String> foo = LazyConstant.of(() -> "hello"); // When skimming the 
code it's not always obvious that this may not be the actual value

void main() {
  if (someCondition()) {
          foo.get(); // Trigger initialization to "hello"
 }
  // If someCondition is false, the final value of foo is determined here:
  var res1 = foo.orElse("hello2"); // ...
}

My Suggestion: I propose introducing a zero-parameter overloaded static factory 
method of():

LazyConstant<String> foo = LazyConstant.of();

This form explicitly communicates that the constant is initialized to an 
unresolved state, suggesting that the value will be determined downstream by 
the first invocation of an initialization/computation method.

LazyConstant<String> foo = LazyConstant.of(); // Clearly unresolved
  void main() {
  if (someCondition()) {
      foo.orElse("hello");
 }
  var res1 = foo.orElse("hello2"); // ...
}

This is specially useful for clarity when one has conditional initialization in 
places such as the constructor of a class. For example


private class Bar{
    LazyConstant<String> foo = LazyConstant.of();
    private Bar(Some some){
        if(some.condition()){
            foo.orElse("foo");
        }
        foo.orElse("foo2");
    }

    String computeValue() {
        return "hello";
    }

    String computeValue2(){
        return "hello2";
    }
}

2. Method Naming Suggestion and and supplier in instance method for consistency 
in the API

My second, much more minor observation relates to the instance method orElse(T 
t).

While orElse fits a retrieval pattern, I personally feel that compute or 
computeIfAbsent would better express the intent of this method, as its primary 
function is not just to retrieve, but to trigger the computation and set the 
final value of the constant if it is currently uninitialized. Also, as the 
factory of() has a supplier i think this instance method should also receive a 
Supplier, This not only keeps the API consistent in the usage but makes more 
ergonomic the declaration of complex initialization logic inside the method.


private class Bar{
    LazyConstant<InitParams> foo = LazyConstant.of(InitParam::default); // 
Under the current API this is mandatory but in reality the value is set in the 
constructor, default is never really used.
    private Bar(Some some){
       foo.compute(some::executeCallToCacheDBAndBringInitializationParams) 
//Real configuration happens here

    }
}

This last it's very common for initialization of configuration classes and 
singletons.


Thank you so much for your attention, I hope you find this feedback useful.

Always yours. David Grajales

Reply via email to