001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.commons.lang; 018 019import static org.apache.juneau.commons.utils.Shorts.*; 020 021import java.lang.reflect.*; 022import java.util.*; 023import java.util.function.*; 024 025import org.apache.juneau.commons.reflect.*; 026import org.apache.juneau.commons.utils.*; 027 028/** 029 * A generic mutable value wrapper. 030 * 031 * <p> 032 * This class provides a simple way to wrap any object type in a mutable container, making it useful for passing 033 * mutable references to lambdas, inner classes, and methods. It is similar to {@link Optional} but allows the 034 * value to be changed after creation. 035 * 036 * <p> 037 * The class supports method chaining through fluent setters and provides various convenience methods for working 038 * with the wrapped value, including mapping, conditional execution, and default value handling. 039 * 040 * <p> 041 * Renamed from {@code Value} in 10.0.0 to resolve an import-name collision with the {@code @Value} injection annotation. 042 * 043 * <h5 class='section'>Features:</h5> 044 * <ul class='spaced-list'> 045 * <li>Mutable value container with fluent API 046 * <li>Optional-like methods: {@link #get()}, {@link #orElse(Object)}, {@link #ifPresent(Consumer)}, {@link #map(Function)} 047 * <li>Atomic-like operations: {@link #getAndSet(Object)}, {@link #getAndUnset()} 048 * <li>Listener support for value changes via {@link ValueListener} 049 * <li>Method chaining for all setter operations 050 * </ul> 051 * 052 * <h5 class='section'>Notes:</h5><ul> 053 * <li class='warn'> 054 * This class is <b>not thread-safe</b>. For concurrent access, consider using atomic classes like 055 * {@link java.util.concurrent.atomic.AtomicReference}. 056 * </ul> 057 * 058 * <h5 class='section'>Examples:</h5> 059 * <p class='bjava'> 060 * <jc>// Basic usage</jc> 061 * Holder<String> <jv>name</jv> = Holder.<jsm>of</jsm>(<js>"John"</js>); 062 * <jv>name</jv>.set(<js>"Jane"</js>); 063 * String <jv>result</jv> = <jv>name</jv>.get(); <jc>// Returns "Jane"</jc> 064 * 065 * <jc>// Use in lambda (effectively final variable)</jc> 066 * Holder<String> <jv>result</jv> = Holder.<jsm>empty</jsm>(); 067 * list.forEach(<jv>x</jv> -> { 068 * <jk>if</jk> (<jv>x</jv>.matches(criteria)) { 069 * <jv>result</jv>.set(<jv>x</jv>); 070 * } 071 * }); 072 * 073 * <jc>// With default values</jc> 074 * Holder<String> <jv>optional</jv> = Holder.<jsm>empty</jsm>(); 075 * String <jv>value</jv> = <jv>optional</jv>.orElse(<js>"default"</js>); <jc>// Returns "default"</jc> 076 * 077 * <jc>// Mapping values</jc> 078 * Holder<Integer> <jv>number</jv> = Holder.<jsm>of</jsm>(5); 079 * Holder<String> <jv>text</jv> = <jv>number</jv>.map(Object::toString); <jc>// Holder of "5"</jc> 080 * 081 * <jc>// With listener for change notification</jc> 082 * Holder<String> <jv>monitored</jv> = Holder.<jsm>of</jsm>(<js>"initial"</js>) 083 * .listener(<jv>newValue</jv> -> <jsm>log</jsm>(<js>"Value changed to: "</js> + <jv>newValue</jv>)); 084 * <jv>monitored</jv>.set(<js>"updated"</js>); <jc>// Triggers listener</jc> 085 * </p> 086 * 087 * <h5 class='section'>Specialized Value Classes:</h5> 088 * <p> 089 * For primitive types and common use cases, specialized subclasses are available with additional convenience methods: 090 * <ul class='spaced-list'> 091 * <li>{@link IntegerHolder} - For mutable integers with {@code getAndIncrement()} 092 * <li>{@link LongHolder} - For mutable longs with {@code getAndIncrement()} 093 * <li>{@link ShortHolder} - For mutable shorts with {@code getAndIncrement()} 094 * <li>{@link FloatHolder} - For mutable floats 095 * <li>{@link DoubleHolder} - For mutable doubles 096 * <li>{@link CharHolder} - For mutable characters 097 * <li>{@link BooleanHolder} - For nullable booleans with {@code isTrue()}/{@code isNotTrue()} 098 * <li>{@link Flag} - For non-nullable boolean flags (true/false only, no null state) 099 * </ul> 100 * 101 * <h5 class='section'>See Also:</h5><ul> 102 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsLang">Lang Package</a> 103 * <li class='jc'>{@link ValueListener} 104 * <li class='jc'>{@link IntegerHolder} 105 * <li class='jc'>{@link BooleanHolder} 106 * <li class='jc'>{@link Flag} 107 * </ul> 108 * 109 * @param <T> The value type. 110 */ 111@SuppressWarnings({ 112 "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants 113 "java:S3740" // Raw Consumer/Supplier types used in value holder utility where callback type parameter cannot be further bounded 114}) 115public class Holder<T> { 116 117 /** 118 * Creates a new empty value (with <c>null</c> as the initial value). 119 * 120 * <h5 class='section'>Example:</h5> 121 * <p class='bjava'> 122 * Holder<String> <jv>value</jv> = Holder.<jsm>empty</jsm>(); 123 * <jsm>assertNull</jsm>(<jv>value</jv>.get()); 124 * <jsm>assertTrue</jsm>(<jv>value</jv>.isEmpty()); 125 * </p> 126 * 127 * @param <T> The value type. 128 * @return A new empty {@link Holder} object. 129 */ 130 public static <T> Holder<T> empty() { 131 return new Holder<>(null); 132 } 133 134 /** 135 * Convenience method for checking if the specified type is this class. 136 * 137 * @param t The type to check. Can be <jk>null</jk> (returns <jk>false</jk>). 138 * @return <jk>true</jk> if the specified type is this class. 139 */ 140 public static boolean isType(Type t) { 141 return (t instanceof ParameterizedType t2 && t2.getRawType() == Holder.class) || (t instanceof Class t3 && Holder.class.isAssignableFrom(t3)); 142 } 143 144 /** 145 * Creates a new value with the specified initial value. 146 * 147 * <h5 class='section'>Example:</h5> 148 * <p class='bjava'> 149 * Holder<String> <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"hello"</js>); 150 * <jsm>assertEquals</jsm>(<js>"hello"</js>, <jv>value</jv>.get()); 151 * </p> 152 * 153 * @param <T> The value type. 154 * @param object The object being wrapped. Can be <jk>null</jk>. 155 * @return A new {@link Holder} object containing the specified value. 156 */ 157 public static <T> Holder<T> of(T object) { 158 return new Holder<>(object); 159 } 160 161 /** 162 * Returns the generic parameter type of the Holder type. 163 * 164 * @param t The type to find the parameter type of. Can be <jk>null</jk> (returns <jk>null</jk>). 165 * @return The parameter type of the value, or <jk>null</jk> if the type is not a subclass of <c>Holder</c>. 166 */ 167 public static Type getParameterType(Type t) { 168 if (t instanceof ParameterizedType t2) { 169 if (t2.getRawType() == Holder.class) { 170 var ta = t2.getActualTypeArguments(); 171 if (ta.length > 0) 172 return ta[0]; 173 } 174 } else if ((t instanceof Class<?> t3) && Holder.class.isAssignableFrom(t3)) { 175 return ClassInfo.of(t3).getParameterType(0, Holder.class); 176 } 177 178 return null; 179 } 180 181 /** 182 * Returns the unwrapped type. 183 * 184 * @param t The type to unwrap. Can be <jk>null</jk> (returns <jk>null</jk>). 185 * @return The unwrapped type, or the same type if the type isn't {@link Holder}. 186 */ 187 public static Type unwrap(Type t) { 188 var x = getParameterType(t); 189 return nn(x) ? x : t; 190 } 191 192 private T t; 193 private ValueListener<T> listener; 194 195 /** 196 * Constructor. 197 */ 198 public Holder() {} 199 200 /** 201 * Constructor. 202 * 203 * @param t Initial value. Can be <jk>null</jk>. 204 */ 205 public Holder(T t) { 206 set(t); 207 } 208 209 @Override /* Overridden from Object */ 210 public boolean equals(Object obj) { 211 return obj instanceof Holder<?> obj2 && eq(this, obj2, (x, y) -> eq(x.t, y.t)); 212 } 213 214 /** 215 * If a value is present, and the value matches the given predicate, returns a {@link Holder} describing the 216 * value, otherwise returns an empty {@link Holder}. 217 * 218 * <p> 219 * This method is analogous to {@link Optional#filter(Predicate)}. 220 * 221 * <h5 class='section'>Example:</h5> 222 * <p class='bjava'> 223 * Holder<String> <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"hello"</js>); 224 * Holder<String> <jv>filtered</jv> = <jv>value</jv>.filter(<jv>s</jv> -> <jv>s</jv>.length() > 3); 225 * <jsm>assertTrue</jsm>(<jv>filtered</jv>.isPresent()); 226 * 227 * Holder<String> <jv>filtered2</jv> = <jv>value</jv>.filter(<jv>s</jv> -> <jv>s</jv>.length() > 10); 228 * <jsm>assertFalse</jsm>(<jv>filtered2</jv>.isPresent()); 229 * </p> 230 * 231 * @param predicate The predicate to apply to the value, if present. Must not be <jk>null</jk>. 232 * @return A {@link Holder} describing the value if it is present and matches the predicate, otherwise an empty {@link Holder}. 233 */ 234 public Holder<T> filter(Predicate<? super T> predicate) { 235 reqnn("predicate", predicate); 236 if (t == null) 237 return Holder.empty(); 238 return predicate.test(t) ? this : Holder.empty(); 239 } 240 241 /** 242 * If a value is present, returns the result of applying the given {@link Holder}-bearing mapping function to 243 * the value, otherwise returns an empty {@link Holder}. 244 * 245 * <p> 246 * This method is similar to {@link #map(Function)}, but the mapping function returns a {@link Holder} rather 247 * than a simple value. This is analogous to {@link Optional#flatMap(Function)}. 248 * 249 * <h5 class='section'>Example:</h5> 250 * <p class='bjava'> 251 * Holder<String> <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"hello"</js>); 252 * Holder<Integer> <jv>length</jv> = <jv>value</jv>.flatMap(<jv>s</jv> -> Holder.<jsm>of</jsm>(<jv>s</jv>.length())); 253 * <jsm>assertEquals</jsm>(5, <jv>length</jv>.get()); 254 * 255 * <jc>// Returns empty if mapper returns empty</jc> 256 * Holder<String> <jv>empty</jv> = <jv>value</jv>.flatMap(<jv>s</jv> -> Holder.<jsm>empty</jsm>()); 257 * <jsm>assertFalse</jsm>(<jv>empty</jv>.isPresent()); 258 * </p> 259 * 260 * @param <T2> The type of value in the {@link Holder} returned by the mapping function. 261 * @param mapper The mapping function to apply to the value, if present. Must not be <jk>null</jk>. 262 * @return The result of applying the {@link Holder}-bearing mapping function to the value if present, 263 * otherwise an empty {@link Holder}. 264 */ 265 @SuppressWarnings({ 266 "unchecked" // Type erasure requires cast to Holder<T2> 267 }) 268 public <T2> Holder<T2> flatMap(Function<? super T,? extends Holder<? extends T2>> mapper) { 269 reqnn("mapper", mapper); 270 if (t == null) 271 return Holder.empty(); 272 var result = mapper.apply(t); 273 return (Holder<T2>)result; 274 } 275 276 /** 277 * Returns the value. 278 * 279 * @return The value, or <jk>null</jk> if it is not set. 280 */ 281 public T get() { 282 return t; 283 } 284 285 /** 286 * Returns the current value and then sets it to the specified value. 287 * 288 * <h5 class='section'>Example:</h5> 289 * <p class='bjava'> 290 * Holder<String> <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"old"</js>); 291 * String <jv>oldValue</jv> = <jv>value</jv>.getAndSet(<js>"new"</js>); <jc>// Returns "old"</jc> 292 * String <jv>newValue</jv> = <jv>value</jv>.get(); <jc>// Returns "new"</jc> 293 * </p> 294 * 295 * @param t The new value. Can be <jk>null</jk>. 296 * @return The value before it was set. 297 */ 298 public T getAndSet(T t) { 299 var t2 = this.t; 300 set(t); 301 return t2; 302 } 303 304 /** 305 * Returns the current value and then unsets it (sets to <jk>null</jk>). 306 * 307 * <p> 308 * This is useful for "consuming" a value, ensuring it can only be retrieved once. 309 * 310 * <h5 class='section'>Example:</h5> 311 * <p class='bjava'> 312 * Holder<String> <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"data"</js>); 313 * String <jv>result</jv> = <jv>value</jv>.getAndUnset(); <jc>// Returns "data"</jc> 314 * <jsm>assertNull</jsm>(<jv>value</jv>.get()); <jc>// Value is now null</jc> 315 * </p> 316 * 317 * @return The value before it was unset, or <jk>null</jk> if it was already <jk>null</jk>. 318 */ 319 public T getAndUnset() { 320 var t2 = t; 321 t = null; 322 return t2; 323 } 324 325 @Override /* Overridden from Object */ 326 public int hashCode() { 327 return t == null ? 0 : t.hashCode(); 328 } 329 330 /** 331 * If a value is present (not <jk>null</jk>), invokes the specified consumer with the value, otherwise does nothing. 332 * 333 * <h5 class='section'>Example:</h5> 334 * <p class='bjava'> 335 * Holder<String> <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"hello"</js>); 336 * <jv>value</jv>.ifPresent(<jsm>System.out</jsm>::<jv>println</jv>); <jc>// Prints "hello"</jc> 337 * 338 * Holder<String> <jv>empty</jv> = Holder.<jsm>empty</jsm>(); 339 * <jv>empty</jv>.ifPresent(<jsm>System.out</jsm>::<jv>println</jv>); <jc>// Does nothing</jc> 340 * </p> 341 * 342 * @param consumer Block to be executed if a value is present. Must not be <jk>null</jk>. 343 */ 344 public void ifPresent(Consumer<? super T> consumer) { 345 if (nn(t)) 346 consumer.accept(t); 347 } 348 349 /** 350 * Checks if the current value equals the specified value using {@link Shorts#eq(Object, Object)}. 351 * 352 * <p> 353 * This method uses {@code eq()} for equality comparison, which handles <jk>null</jk> values safely 354 * and performs deep equality checks for arrays and collections. 355 * 356 * <h5 class='section'>Example:</h5> 357 * <p class='bjava'> 358 * Holder<String> <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"hello"</js>); 359 * <jsm>assertTrue</jsm>(<jv>value</jv>.is(<js>"hello"</js>)); 360 * <jsm>assertFalse</jsm>(<jv>value</jv>.is(<js>"world"</js>)); 361 * 362 * <jc>// Handles null values safely</jc> 363 * Holder<String> <jv>empty</jv> = Holder.<jsm>empty</jsm>(); 364 * <jsm>assertTrue</jsm>(<jv>empty</jv>.is(<jk>null</jk>)); 365 * <jsm>assertFalse</jsm>(<jv>empty</jv>.is(<js>"test"</js>)); 366 * 367 * <jc>// Works with any type</jc> 368 * Holder<Integer> <jv>number</jv> = Holder.<jsm>of</jsm>(42); 369 * <jsm>assertTrue</jsm>(<jv>number</jv>.is(42)); 370 * <jsm>assertFalse</jsm>(<jv>number</jv>.is(43)); 371 * </p> 372 * 373 * @param other The value to compare with. Can be <jk>null</jk>. 374 * @return <jk>true</jk> if the values are equal according to {@link Shorts#eq(Object, Object)}. 375 */ 376 public boolean is(T other) { 377 return eq(t, other); 378 } 379 380 /** 381 * Returns <jk>true</jk> if the value is empty. 382 * 383 * @return <jk>true</jk> if the value is empty. 384 */ 385 public boolean isEmpty() { return t == null; } 386 387 /** 388 * Returns <jk>true</jk> if the value is set. 389 * 390 * @return <jk>true</jk> if the value is set. 391 */ 392 public boolean isPresent() { return nn(get()); } 393 394 /** 395 * Registers a listener that will be called whenever the value is changed via {@link #set(Object)}. 396 * 397 * <p> 398 * Only one listener can be registered at a time. Calling this method again will replace the previous listener. 399 * 400 * <h5 class='section'>Example:</h5> 401 * <p class='bjava'> 402 * Holder<String> <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"initial"</js>); 403 * <jv>value</jv>.listener(<jv>newValue</jv> -> <jsm>log</jsm>(<js>"Changed to: "</js> + <jv>newValue</jv>)); 404 * 405 * <jv>value</jv>.set(<js>"updated"</js>); <jc>// Triggers listener, logs "Changed to: updated"</jc> 406 * </p> 407 * 408 * @param listener The listener to be called on value changes. Can be <jk>null</jk> to remove the listener. 409 * @return This object for method chaining. 410 * @see ValueListener 411 */ 412 public Holder<T> listener(ValueListener<T> listener) { 413 this.listener = listener; 414 return this; 415 } 416 417 /** 418 * Applies a mapping function to the value if present, returning a new {@link Holder} with the result. 419 * 420 * <p> 421 * If this value is empty (<jk>null</jk>), returns an empty value without applying the mapper. 422 * 423 * <h5 class='section'>Example:</h5> 424 * <p class='bjava'> 425 * Holder<String> <jv>name</jv> = Holder.<jsm>of</jsm>(<js>"john"</js>); 426 * Holder<String> <jv>upper</jv> = <jv>name</jv>.map(String::toUpperCase); 427 * <jsm>assertEquals</jsm>(<js>"JOHN"</js>, <jv>upper</jv>.get()); 428 * 429 * Holder<Integer> <jv>length</jv> = <jv>name</jv>.map(String::length); 430 * <jsm>assertEquals</jsm>(4, <jv>length</jv>.get()); 431 * 432 * Holder<String> <jv>empty</jv> = Holder.<jsm>empty</jsm>(); 433 * Holder<Integer> <jv>result</jv> = <jv>empty</jv>.map(String::length); <jc>// Returns empty Holder</jc> 434 * </p> 435 * 436 * @param <T2> The mapped value type. 437 * @param mapper The mapping function to apply. Must not be <jk>null</jk>. 438 * @return A new {@link Holder} containing the mapped result, or an empty value if this value is empty. 439 */ 440 public <T2> Holder<T2> map(Function<? super T,T2> mapper) { 441 reqnn("mapper", mapper); 442 if (nn(t)) 443 return of(mapper.apply(t)); 444 return empty(); 445 } 446 447 /** 448 * Returns the contents of this value or the default value if <jk>null</jk>. 449 * 450 * @param def The default value. Can be <jk>null</jk>. 451 * @return The contents of this value or the default value if <jk>null</jk>. 452 */ 453 public T orElse(T def) { 454 return t == null ? def : t; 455 } 456 457 /** 458 * Return the value if present, otherwise invoke {@code other} and return 459 * the result of that invocation. 460 * 461 * @param other a {@code Supplier} whose result is returned if no value 462 * is present 463 * @return the value if present otherwise the result of {@code other.get()} 464 * @throws NullPointerException if value is not present and {@code other} is 465 * null 466 */ 467 public T orElseGet(Supplier<? extends T> other) { 468 return nn(t) ? t : other.get(); 469 } 470 471 /** 472 * Return the contained value, if present, otherwise throw an exception 473 * to be created by the provided supplier. 474 * 475 * @param <X> The exception type. 476 * @param exceptionSupplier The supplier which will return the exception to 477 * be thrown 478 * @return the present value 479 * @throws X if there is no value present 480 * @throws NullPointerException if no value is present and 481 * {@code exceptionSupplier} is null 482 */ 483 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 484 if (nn(t)) 485 return t; 486 throw exceptionSupplier.get(); 487 } 488 489 /** 490 * Sets the value. 491 * 492 * <p> 493 * If a {@link ValueListener} is registered, it will be notified of the change. 494 * 495 * <h5 class='section'>Example:</h5> 496 * <p class='bjava'> 497 * Holder<String> <jv>value</jv> = Holder.<jsm>empty</jsm>(); 498 * <jv>value</jv>.set(<js>"hello"</js>).set(<js>"world"</js>); <jc>// Method chaining</jc> 499 * <jsm>assertEquals</jsm>(<js>"world"</js>, <jv>value</jv>.get()); 500 * </p> 501 * 502 * @param t The new value. Can be <jk>null</jk>. 503 * @return This object for method chaining. 504 */ 505 public Holder<T> set(T t) { 506 this.t = t; 507 if (nn(listener)) 508 listener.onSet(t); 509 return this; 510 } 511 512 /** 513 * Sets the value only if the specified condition is <jk>true</jk>. 514 * 515 * <h5 class='section'>Example:</h5> 516 * <p class='bjava'> 517 * Holder<String> <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"old"</js>); 518 * <jv>value</jv>.setIf(<jk>true</jk>, <js>"new"</js>); <jc>// Sets to "new"</jc> 519 * <jv>value</jv>.setIf(<jk>false</jk>, <js>"newer"</js>); <jc>// Does nothing</jc> 520 * <jsm>assertEquals</jsm>(<js>"new"</js>, <jv>value</jv>.get()); 521 * </p> 522 * 523 * @param condition The condition to check. 524 * @param t The value to set if condition is <jk>true</jk>. Can be <jk>null</jk>. 525 * @return This object. 526 */ 527 public Holder<T> setIf(boolean condition, T t) { 528 if (condition) 529 set(t); 530 return this; 531 } 532 533 /** 534 * Sets the value only if it is currently empty (<jk>null</jk>). 535 * 536 * <p> 537 * If the value is already set, this method does nothing. 538 * 539 * <h5 class='section'>Example:</h5> 540 * <p class='bjava'> 541 * Holder<String> <jv>value</jv> = Holder.<jsm>empty</jsm>(); 542 * <jv>value</jv>.setIfEmpty(<js>"first"</js>); <jc>// Sets value to "first"</jc> 543 * <jv>value</jv>.setIfEmpty(<js>"second"</js>); <jc>// Does nothing, value remains "first"</jc> 544 * <jsm>assertEquals</jsm>(<js>"first"</js>, <jv>value</jv>.get()); 545 * </p> 546 * 547 * @param t The new value. Can be <jk>null</jk>. 548 * @return This object for method chaining. 549 */ 550 public Holder<T> setIfEmpty(T t) { 551 if (isEmpty()) 552 set(t); 553 return this; 554 } 555 556 @Override /* Overridden from Object */ 557 public String toString() { 558 return "Holder(" + t + ")"; 559 } 560 561 /** 562 * Updates the value in-place using the specified function. 563 * 564 * <p> 565 * If the current value is <jk>null</jk>, this is a no-op. 566 * 567 * <h5 class='section'>Example:</h5> 568 * <p class='bjava'> 569 * Holder<String> <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"hello"</js>); 570 * <jv>value</jv>.update(String::toUpperCase); 571 * <jsm>assertEquals</jsm>(<js>"HELLO"</js>, <jv>value</jv>.get()); 572 * 573 * <jc>// No-op when null</jc> 574 * Holder<String> <jv>empty</jv> = Holder.<jsm>empty</jsm>(); 575 * <jv>empty</jv>.update(String::toUpperCase); <jc>// Does nothing</jc> 576 * <jsm>assertNull</jsm>(<jv>empty</jv>.get()); 577 * </p> 578 * 579 * @param updater The function to apply to the current value. Must not be <jk>null</jk>. 580 * @return This object. 581 */ 582 public Holder<T> update(UnaryOperator<T> updater) { 583 if (nn(t)) 584 set(updater.apply(t)); 585 return this; 586 } 587}