A ScopedValue.where(key, value) call creates a ScopedValue.Carrier object that maps a key to a specific value. However, this binding is not active until a functional task is executed through that carrier using methods like .run(Runnable) or .call(Callable).

Why is this an issue?

Calling .where(…​) without a subsequent execution method is a "dead" statement. Unlike ThreadLocal.set(), which modifies the state of the current thread, ScopedValue bindings are only valid within the dynamic scope of a carrier’s execution method.

Ignoring the returned Carrier object means the intended value binding is never established, likely leading to a NoSuchElementException when attempting to access the value.

How to fix it

Chain the .where(…​) call with an execution method such as .run(Runnable) or .call(Callable). This ensures the binding is active for the duration of the provided functional interface’s execution.

Code examples

Noncompliant code example

static final ScopedValue<String> THEME = ScopedValue.newInstance();

public void applySettings() {
    // Noncompliant: The binding is created but never activated.
    ScopedValue.where(THEME, "DARK");
}

Compliant solution

static final ScopedValue<String> THEME = ScopedValue.newInstance();

public void applySettings() {
    // Compliant: The binding is scoped to the execution of the run() method.
    ScopedValue.where(THEME, "DARK").run(this::renderUI);
}

void renderUI() {
    System.out.println("Applying theme: " + THEME.get());
}

Resources

Documentation