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&lt;String&gt; <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&lt;String&gt; <jv>result</jv> = Holder.<jsm>empty</jsm>();
067 *    list.forEach(<jv>x</jv> -&gt; {
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&lt;String&gt; <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&lt;Integer&gt; <jv>number</jv> = Holder.<jsm>of</jsm>(5);
079 *    Holder&lt;String&gt; <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&lt;String&gt; <jv>monitored</jv> = Holder.<jsm>of</jsm>(<js>"initial"</js>)
083 *       .listener(<jv>newValue</jv> -&gt; <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&lt;String&gt; <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&lt;String&gt; <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&lt;String&gt; <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"hello"</js>);
224    *    Holder&lt;String&gt; <jv>filtered</jv> = <jv>value</jv>.filter(<jv>s</jv> -&gt; <jv>s</jv>.length() &gt; 3);
225    *    <jsm>assertTrue</jsm>(<jv>filtered</jv>.isPresent());
226    *
227    *    Holder&lt;String&gt; <jv>filtered2</jv> = <jv>value</jv>.filter(<jv>s</jv> -&gt; <jv>s</jv>.length() &gt; 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&lt;String&gt; <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"hello"</js>);
252    *    Holder&lt;Integer&gt; <jv>length</jv> = <jv>value</jv>.flatMap(<jv>s</jv> -&gt; 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&lt;String&gt; <jv>empty</jv> = <jv>value</jv>.flatMap(<jv>s</jv> -&gt; 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&lt;String&gt; <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&lt;String&gt; <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&lt;String&gt; <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&lt;String&gt; <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&lt;String&gt; <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&lt;String&gt; <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&lt;Integer&gt; <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&lt;String&gt; <jv>value</jv> = Holder.<jsm>of</jsm>(<js>"initial"</js>);
403    *    <jv>value</jv>.listener(<jv>newValue</jv> -&gt; <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&lt;String&gt; <jv>name</jv> = Holder.<jsm>of</jsm>(<js>"john"</js>);
426    *    Holder&lt;String&gt; <jv>upper</jv> = <jv>name</jv>.map(String::toUpperCase);
427    *    <jsm>assertEquals</jsm>(<js>"JOHN"</js>, <jv>upper</jv>.get());
428    *
429    *    Holder&lt;Integer&gt; <jv>length</jv> = <jv>name</jv>.map(String::length);
430    *    <jsm>assertEquals</jsm>(4, <jv>length</jv>.get());
431    *
432    *    Holder&lt;String&gt; <jv>empty</jv> = Holder.<jsm>empty</jsm>();
433    *    Holder&lt;Integer&gt; <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&lt;String&gt; <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&lt;String&gt; <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&lt;String&gt; <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&lt;String&gt; <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&lt;String&gt; <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}