001/*
002 * ============================================================================
003 * Copyright © 2002-2026 by Thomas Thrien.
004 * All Rights Reserved.
005 * ============================================================================
006 *
007 * Licensed to the public under the agreements of the GNU Lesser General Public
008 * License, version 3.0 (the "License"). You may obtain a copy of the License at
009 *
010 *      http://www.gnu.org/licenses/lgpl.html
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015 * License for the specific language governing permissions and limitations
016 * under the License.
017 */
018
019package org.tquadrat.foundation.lang;
020
021import org.apiguardian.api.API;
022import org.tquadrat.foundation.annotation.ClassVersion;
023import org.tquadrat.foundation.annotation.UtilityClass;
024import org.tquadrat.foundation.exception.BlankArgumentException;
025import org.tquadrat.foundation.exception.EmptyArgumentException;
026import org.tquadrat.foundation.exception.NullArgumentException;
027import org.tquadrat.foundation.exception.PrivateConstructorForStaticClassCalledError;
028import org.tquadrat.foundation.exception.ValidationException;
029
030import java.lang.reflect.Array;
031import java.util.Arrays;
032import java.util.Collection;
033import java.util.Collections;
034import java.util.Comparator;
035import java.util.Enumeration;
036import java.util.List;
037import java.util.Map;
038import java.util.Optional;
039import java.util.function.DoublePredicate;
040import java.util.function.Function;
041import java.util.function.IntPredicate;
042import java.util.function.LongPredicate;
043import java.util.function.Predicate;
044import java.util.function.Supplier;
045import java.util.function.UnaryOperator;
046
047import static java.lang.Integer.signum;
048import static java.util.Arrays.deepToString;
049import static org.apiguardian.api.API.Status.STABLE;
050import static org.tquadrat.foundation.lang.CommonConstants.NULL_STRING;
051
052/**
053 *  <p>{@summary This class consists of several utility methods working on
054 *  {@link Object}
055 *  instances, similar to those on
056 *  {@link Arrays}
057 *  or
058 *  {@link Collections}.}</p>
059 *  <p>The class was originally inspired by the class of the same name that
060 *  was finally introduced with the Java&nbsp;7 release; some of its methods
061 *  will delegate to
062 *  {@link java.util.Objects java.util.Objects},
063 *  others will extend the functionality of the methods with the same
064 *  name from {@code java.util.Objects}.</p>
065 *  <p>If a method from {@code java.util.Objects} would throw a
066 *  {@link NullPointerException},
067 *  the method with the same name from this class would throw a
068 *  {@link ValidationException}
069 *  instead.</p>
070 *
071 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
072 *  @version $Id: Objects.java 1163 2026-03-20 15:28:33Z tquadrat $
073 *  @since 0.0.1
074 *
075 *  @UMLGraph.link
076 */
077@UtilityClass
078@SuppressWarnings( {"ClassWithTooManyMethods", "UseOfObsoleteDateTimeApi", "OverlyComplexClass"} )
079@ClassVersion( sourceVersion = "$Id: Objects.java 1163 2026-03-20 15:28:33Z tquadrat $" )
080@API( status = STABLE, since = "0.0.1" )
081public final class Objects
082{
083        /*--------------*\
084    ====** Constructors **=====================================================
085        \*--------------*/
086    /**
087     *  No instance allowed for this class.
088     */
089    private Objects() { throw new PrivateConstructorForStaticClassCalledError( Objects.class ); }
090
091        /*---------*\
092    ====** Methods **==========================================================
093        \*---------*/
094    /**
095     *  <p>{@summary Checks if the sub-range from {@code fromIndex} (inclusive)
096     *  to {@code fromIndex + size} (exclusive) is within the bounds of range
097     *  from {@code 0} (inclusive) to {@code length} (exclusive).}</p>
098     *  <p>The sub-range is defined to be out-of-bounds if any of the following
099     *  inequalities is true:</p>
100     *  <ul>
101     *    <li>{@code fromIndex < 0}</li>
102     *    <li>{@code size < 0}</li>
103     *    <li>{@code fromIndex + size > length}, taking into account integer
104     *    overflow</li>
105     *    <li>{@code length < 0}, which is implied from the former
106     *    inequalities</li>
107     *  </ul>
108     *  <p>Calls
109     *  {@link java.util.Objects#checkFromIndexSize(int,int,int) java.util.Objects.checkFromIndexSize(int,int,int)}
110     *  internally.</p>
111     *
112     *  @param  fromIndex   The lower-bound (inclusive) of the sub-interval.
113     *  @param  size    The size of the sub-range.
114     *  @param  length  The upper-bound (exclusive) of the range.
115     *  @return The {@code fromIndex} if the sub-range is within bounds of the
116     *      range.
117     *  @throws IndexOutOfBoundsException   The sub-range is out-of-bounds.
118     *
119     *  @since 0.0.5
120     */
121    @API( status = STABLE, since = "0.0.5" )
122    public static final int checkFromIndexSize( final int fromIndex, final int size, final int length )
123    {
124        final var retValue = java.util.Objects.checkFromIndexSize( fromIndex, size, length );
125
126        //---* Done *----------------------------------------------------------
127        return retValue;
128    }   //  checkFromIndexSize()
129
130    /**
131     *  <p>{@summary Checks if the sub-range from {@code fromIndex} (inclusive)
132     *  to {@code toIndex} (exclusive) is within the bounds of range from
133     *  {@code 0} (inclusive) to {@code length} (exclusive).}</p>
134     *  <p>The sub-range is defined to be out-of-bounds if any of the following
135     *  inequalities is true:</p>
136     *  <ul>
137     *    <li>{@code fromIndex < 0}</li>
138     *    <li>{@code fromIndex > toIndex}</li>
139     *    <li>{@code toIndex > length}</li>
140     *    <li>{@code length < 0}, which is implied from the former
141     *    inequalities</li>
142     *  </ul>
143     *  <p>Calls
144     *  {@link java.util.Objects#checkFromToIndex(int,int,int) java.util.Objects.checkFromToIndex(int,int,int)}
145     *  internally.</p>
146     *
147     *  @param  fromIndex   The lower-bound (inclusive) of the sub-range.
148     *  @param  toIndex The upper-bound (exclusive) of the sub-range.
149     *  @param  length  The upper-bound (exclusive) the range.
150     *  @return The {@code fromIndex} if the sub-range is within bounds of the
151     *      range.
152     *  @throws IndexOutOfBoundsException   The sub-range is out-of-bounds.
153     *
154     *  @since 0.0.5
155     */
156    @API( status = STABLE, since = "0.0.5" )
157    public static final int checkFromToIndex( final int fromIndex, final int toIndex, final int length )
158    {
159        final var retValue = java.util.Objects.checkFromToIndex( fromIndex, toIndex, length );
160
161        //---* Done *----------------------------------------------------------
162        return retValue;
163    }   //  checkFromToIndex()
164
165    /**
166     *  <p>{@summary Checks if the {@code index} is within the bounds of the
167     *  range from {@code 0} (inclusive) to {@code length} (exclusive).}</p>
168     *  <p>The {@code index} is defined to be out-of-bounds if any of the
169     *  following inequalities is true:</p>
170     *  <ul>
171     *    <li>{@code index < 0}</li>
172     *    <li>{@code index >= length}</li>
173     *    <li>{@code length < 0}, which is implied from the former
174     *    inequalities</li>
175     *  </ul>
176     *  <p>Calls
177     *  {@link java.util.Objects#checkIndex(int,int) java.util.Objects.checkIndex(int,int)}
178     *  internally.</p>
179     *
180     *  @param  index   The index.
181     *  @param  length  The upper-bound (exclusive) of the range.
182     *  @return The {@code index} if it is within bounds of the range.
183     *  @throws IndexOutOfBoundsException   The {@code index} is out-of-bounds.
184     *
185     *  @since 0.0.5
186     */
187    @API( status = STABLE, since = "0.0.5" )
188    public static final int checkIndex( final int index, final int length )
189    {
190        final var retValue = java.util.Objects.checkIndex( index, length );
191
192        //---* Done *----------------------------------------------------------
193        return retValue;
194    }   //  checkIndex()
195
196    /**
197     *  <p>{@summary Throws the exception provided by the given supplier if the
198     *  condition resolves to {@code false}.}</p>
199     *  <p>Basically, this method is a replacement for the code sequence
200     *  below:</p>
201     *  <div class="source-container"><pre>…
202     *  if( !&lt;<i>condition</i>&gt; )
203     *  {
204     *      throw new &lt;<i>WhatEver</i>&gt;Exception( &lt;<i>WhatEverMessage</i>&gt; );
205     *  }
206     *  …</pre></div>
207     *  <p>Code using this method may be easier to read than the {@code if}
208     *  statement above:</p>
209     *  <div class="source-container"><pre>…
210     *  checkState( &lt;<i>condition</i>&gt;, () -> new &lt;<i>WhatEver</i>&gt;Exception( &lt;<i>WhatEverMessage</i>&gt; ) );
211     *  …</pre></div>
212     *
213     *  @param  <E> The type of the exception that is thrown in case the
214     *      condition is not met.
215     *  @param  condition   The condition to check.
216     *  @param  exception   The exception to throw.
217     *  @throws E   The condition was not met.
218     */
219    @SuppressWarnings( "CheckedExceptionClass" )
220    public static final <E extends Exception> void checkState( final boolean condition, final Supplier<E> exception ) throws E
221    {
222        if( !condition ) throw requireNonNullArgument( exception, "exception" ).get();
223    }   //  checkState()
224
225    /**
226     *  <p>{@summary Returns 0 if the arguments are identical and
227     *  {@code comparator.compare(a, b)} otherwise.}</p>
228     *  <p>Consequently, if both arguments are {@code null}, 0 is returned.</p>
229     *  <p>Calls
230     *  {@link java.util.Objects#compare(Object,Object,Comparator) java.util.Objects#compare()}
231     *  internally, but different from that method, this implementation will
232     *  throw a
233     *  {@link NullArgumentException}
234     *  in case the {@code comparator} is {@code null}.</p>
235     *
236     *  @param  <T> The type of the objects being compared.
237     *  @param  object  An object.
238     *  @param  other   Another object to be compared with the first object.
239     *  @param  comparator  The
240     *      {@link Comparator}
241     *      to compare the first two arguments.
242     *  @return 0 if the arguments are identical and +1, 0, or -1, based on the
243     *      return value of {@code c.compare(a, b)} otherwise.
244     *  @throws NullArgumentException   The {@code comparator} is {@code null}.
245     *
246     *  @see Comparable
247     *  @see Comparator
248     *
249     *  @since 0.0.5
250     */
251    @API( status = STABLE, since = "0.0.5" )
252    public static final <T> int compare( final T object, final T other, final Comparator<? super T> comparator ) throws NullArgumentException
253    {
254        final var retValue = object == other ? 0 : signum( java.util.Objects.compare( object, other, requireNonNullArgument( comparator, "comparator" ) ) );
255
256        //---* Done *----------------------------------------------------------
257        return retValue;
258    }   //  compare()
259
260    /**
261     *  <p>{@summary Returns {@code true} if the arguments are deeply equal to
262     *  each other and {@code false} otherwise.}</p>
263     *  <p>Two {@code null} values are deeply equal. If both arguments are
264     *  arrays, the algorithm in
265     *  {@link Arrays#deepEquals(Object[], Object[]) Arrays.deepEquals()}
266     *  is used to determine equality. Otherwise, equality is determined by
267     *  using the
268     *  {@link Object#equals(Object) equals()}
269     *  method of the first argument.</p>
270     *  <p>Calls
271     *  {@link java.util.Objects#deepEquals(Object,Object) java.util.Objects#deepEquals()}
272     *  internally.</p>
273     *
274     *  @param  object  An object.
275     *  @param  other   Another object to be compared with the first object for
276     *      deep equality.
277     *  @return {@code true} if the arguments are deeply equal to each other
278     *      and {@code false} otherwise.
279     *
280     *  @see    Arrays#deepEquals(Object[],Object[])
281     *  @see    Objects#equals(Object,Object)
282     *
283     *  @since 0.0.5
284     */
285    @SuppressWarnings( "BooleanMethodNameMustStartWithQuestion" )
286    @API( status = STABLE, since = "0.0.5" )
287    public static final boolean deepEquals( final Object object, final Object other ) { return java.util.Objects.deepEquals( object, other ); }
288
289    /**
290     *  <p>{@summary Returns {@code true} if the arguments are equal to each
291     *  other and {@code false} otherwise.}</p>
292     *  <p> Consequently, if both arguments are {@code null}, {@code true} is
293     *  returned and if exactly one argument is {@code null}, {@code false} is
294     *  returned.  Otherwise, equality is determined by using the
295     *  {@link Object#equals(Object) equals()}
296     *  method of the first argument.</p>
297     *  <p>Calls
298     *  {@link java.util.Objects#equals(Object, Object)}
299     *  internally.</p>
300     *
301     *  @param  object  An object.
302     *  @param  other   Another object to be compared with the first one for
303     *      equality.
304     *  @return {@code true} if the arguments are equal to each other and
305     *      {@code false} otherwise.
306     *
307     *  @see    Object#equals(Object)
308     *
309     *  @since 0.0.5
310     */
311    @API( status = STABLE, since = "0.0.5" )
312    public static final boolean equals( final Object object, final Object other ) { return java.util.Objects.equals( object, other ); }
313
314    /**
315     *  <p>{@summary Generates a hash code for a sequence of input values.} The
316     *  hash code is generated as if all the input values were placed into an
317     *  array, and that array is hashed by calling
318     *  {@link Arrays#hashCode(Object[])}.</p>
319     *  <p>Calls
320     *  {@link java.util.Arrays#hashCode(Object[]) java.util.Arrays.hashCode()}
321     *  internally.</p>
322     *
323     *  @param  values  The values to be hashed.
324     *  @return A hash value of the sequence of input values.
325     *
326     *  @see    List#hashCode
327     *
328     *  @since 0.0.5
329     */
330    @API( status = STABLE, since = "0.0.5" )
331    public static final int hash( final Object... values ) { return Arrays.hashCode( values ); }
332
333    /**
334     *  <p>{@summary Returns the hash code of a non-{@code null} argument and 0
335     *  for a {@code null} argument.}</p>
336     *  <p>Calls
337     *  {@link java.util.Objects#hashCode(Object) java.util.Objects.hashCode(Object)}
338     *  internally.</p>
339     *
340     *  @param o   An object.
341     *  @return The hash code of an argument that is not {@code null}, and 0
342     *      for a {@code null} argument,
343     *
344     *  @see    Object#hashCode
345     *
346     *  @since 0.0.5
347     */
348    @API( status = STABLE, since = "0.0.5" )
349    public static final int hashCode( final Object o ) { return java.util.Objects.hashCode( o ); }
350
351    /**
352     *  <p>{@summary Returns {@code true} if the provided reference is
353     *  {@code null}, otherwise returns {@code false}.}</p>
354     *  <p>This method can be used as a
355     *  {@link java.util.function.Predicate},
356     *  {@code filter(Objects::isNull)}.</p>
357     *  <p>Calls
358     *  {@link java.util.Objects#isNull(Object) java.util.Objects.isNull()}
359     *  internally.</p>
360     *
361     *  @param  obj A reference to be checked against {@code null}.
362     *  @return {@code true} if the provided reference is {@code null},
363     *      otherwise {@code false}
364     *
365     *  @see    java.util.function.Predicate
366     *  @see    org.tquadrat.foundation.lang.CommonConstants#IS_NULL
367     *
368     *  @since 0.0.5
369     */
370    @API( status = STABLE, since = "0.0.5" )
371    public static final boolean isNull( final Object obj ) { return java.util.Objects.isNull( obj ); }
372
373    /**
374     *  <p>{@summary Provides a replacement value if the given value is
375     *  {@code null}.}</p>
376     *  <p>This is basically a shortcut to</p>
377     *  <div class="source-container"><pre>Optional.ofNullable( value ).orElseGet( supplier );</pre></div>
378     *
379     *  @param  <T> The type of the object to map.
380     *  @param  value   The object to map; can be {@code null} (obviously).
381     *  @param  supplier    The supplier for the replacement function.
382     *  @return The provided object if that is not {@code null}, or the result
383     *      from the supplier method. Keep in mind that this result can be
384     *      {@code null}!
385     *
386     *  @see Optional
387     *  @see Optional#orElseGet(Supplier)
388     *
389     *  @since 0.2.2
390     */
391    @API( status = STABLE, since = "0.2.2" )
392    public static final <T> T mapFromNull( final T value, final Supplier<? extends T> supplier )
393    {
394        requireNonNullArgument( supplier, "supplier" );
395        final var retValue = isNull( value )
396            ? supplier.get()
397            : value;
398
399        //---* Done *----------------------------------------------------------
400        return retValue;
401    }   //  mapFromNull()
402
403    /**
404     *  <p>{@summary Provides a replacement value if the given value is
405     *  {@code null}.}</p>
406     *  <p>This is basically a shortcut to</p>
407     *  <div class="source-container"><pre>Optional.ofNullable( value ).orElse( replacement );</pre></div>
408     *
409     *  @param  <T> The type of the object to map.
410     *  @param  value   The object to map; can be {@code null}.
411     *  @param  replacement  The replacement value; it may not be {@code null}.
412     *  @return The provided object if that is not {@code null}, or the
413     *      replacement value.
414     *
415     *  @see Optional
416     *  @see Optional#orElse(Object)
417     *
418     *  @since 0.4.2
419     */
420    @API( status = STABLE, since = "0.4.2" )
421    public static final <T> T mapFromNull( final T value, final T replacement )
422    {
423        requireNonNullArgument( replacement, "replacement" );
424        final var retValue = isNull( value )
425                             ? replacement
426                             : value;
427
428        //---* Done *----------------------------------------------------------
429        return retValue;
430    }   //  mapFromNull()
431
432    /**
433     *  <p>{@summary Maps (converts) the given object instance by applying the
434     *  provided mapper if the instance is not {@code null}.}</p>
435     *  <p>The mapper function will not be called at all if the given instance
436     *  is {@code null}.</p>
437     *
438     *  @param  <T> The type of the object to map.
439     *  @param  <R> The type of the result.
440     *  @param  o   The object to map; can be {@code null}.
441     *  @param  mapper  The mapping function.
442     *  @return The result of the mapping, or {@code null} if the given object
443     *      instance was already {@code null}. Keep in mind that the result of
444     *      the mapping can be {@code null}!
445     */
446    public static final <T,R> R mapNonNull( final T o, final Function<T,? extends R> mapper )
447    {
448        @SuppressWarnings( "RedundantExplicitVariableType" )
449        final R retValue = nonNull( o ) ? requireNonNullArgument( mapper, "mapper" ).apply( o ) : null;
450
451        //---* Done *----------------------------------------------------------
452        return retValue;
453    }   //  mapNonNull()
454
455    /**
456     *  <p>{@summary Maps (converts) the given object instance by applying the
457     *  provided mapper if the instance is not {@code null} or returns the
458     *  given default value.}</p>
459     *  <p>The mapper function will not be called at all if the given instance
460     *  is {@code null}.</p>
461     *
462     *  @param  <T> The type of the object to map.
463     *  @param  <R> The type of the result.
464     *  @param  o   The object to map; can be {@code null}.
465     *  @param  mapper  The mapping function.
466     *  @param  defaultValue    The default value; can be {@code null}.
467     *  @return The result of the mapping, or the default value if the given
468     *      object instance is {@code null}. Keep in mind that the result of
469     *      the mapping can be {@code null}!
470     */
471    public static final <T,R> R mapNonNull( final T o, final Function<T,? extends R> mapper, final R defaultValue )
472    {
473        @SuppressWarnings( "RedundantExplicitVariableType" )
474        final R retValue = nonNull( o ) ? requireNonNullArgument( mapper, "mapper" ).apply( o ) : defaultValue;
475
476        //---* Done *----------------------------------------------------------
477        return retValue;
478    }   //  mapNonNull()
479
480    /**
481     *  <p>{@summary Returns {@code true} if the provided reference is not
482     *  {@code null}, otherwise returns {@code false}.}</p>
483     *  <p>This method exists to be used as a
484     *  {@link java.util.function.Predicate},
485     *  {@code filter(Objects::nonNull)}</p>
486     *  <p>Calls
487     *  {@link java.util.Objects#nonNull(Object) java.util.Objects.nonNull()}
488     *  internally.</p>
489     *
490     *  @param  obj A reference to be checked against {@code null}
491     *  @return {@code false} if the provided reference is {@code null},
492     *      otherwise {@code true}
493     *
494     *  @see java.util.function.Predicate
495     *  @see org.tquadrat.foundation.lang.CommonConstants#NON_NULL
496     *
497     *  @since 0.0.5
498     */
499    @SuppressWarnings( "BooleanMethodNameMustStartWithQuestion" )
500    @API( status = STABLE, since = "0.0.5" )
501    public static final boolean nonNull( final Object obj ) { return java.util.Objects.nonNull( obj ); }
502
503    /**
504     *  Applies the given validation on the given value, and if that fails, an
505     *  {@link ValidationException}
506     *  is thrown.
507     *
508     *  @param  <T> The type of the value to check.
509     *  @param  obj The value to check; can be {@code null}.
510     *  @param  validation  The validation
511     *  @return The value if the validation succeeds.
512     *  @throws ValidationException {@code obj} failed the validation.
513     *
514     *  @since 0.1.0
515     */
516    @SuppressWarnings( "NewExceptionWithoutArguments" )
517    @API( status = STABLE, since = "0.1.0" )
518    public static final <T> T require( final T obj, final Predicate<? super T> validation ) throws ValidationException
519    {
520        if( !requireNonNullArgument( validation, "validation" ).test( obj ) )
521        {
522            throw new ValidationException();
523        }
524
525        //---* Done *----------------------------------------------------------
526        return obj;
527    }   //  require()
528
529    /**
530     *  Applies the given validation on the given value, and if that fails, an
531     *  {@link ValidationException}
532     *  with the specified message is thrown.
533     *
534     *  @param  <T> The type of the value to check.
535     *  @param  obj The value to check; can be {@code null}.
536     *  @param  message The message that is set to the thrown exception.
537     *  @param  validation  The validation
538     *  @return The value if the validation succeeds.
539     *  @throws ValidationException {@code obj} failed the validation.
540     *  @throws NullArgumentException   {@code message} is {@code null}.
541     *  @throws EmptyArgumentException  {@code message} is the empty String.
542     *
543     *  @since 0.1.0
544     */
545    @API( status = STABLE, since = "0.1.0" )
546    public static final <T> T require( final T obj, final String message, final Predicate<? super T> validation ) throws ValidationException, NullArgumentException, EmptyArgumentException
547    {
548        requireNotEmptyArgument( message, "message" );
549
550        if( !requireNonNullArgument( validation, "validation" ).test( obj ) )
551        {
552            throw new ValidationException( message );
553        }
554
555        //---* Done *----------------------------------------------------------
556        return obj;
557    }   //  require()
558
559    /**
560     *  <p>{@summary Applies the given validation on the given value, and if
561     *  that fails, a customized
562     *  {@link ValidationException}
563     *  is thrown.}</p>
564     *  <p>Unlike the method
565     *  {@link #require(Object,String,Predicate)},
566     *  this method allows to defer the creation of the message until after the
567     *  validation was performed (and failed). While this may confer a
568     *  performance advantage in the success case, some care should be taken
569     *  that the costs for the creation of the message supplier are less than
570     *  the cost of just creating the String message directly.</p>
571     *
572     *  @param  <T> The type of the value to check.
573     *  @param  obj The value to check; can be {@code null}.
574     *  @param  messageSupplier The supplier of the detail message to be used
575     *      in the event that {@code ValidationException} is thrown. If
576     *      {@code null} or if it returns {@code null}, no detail message is
577     *      provided to the exception.
578     *  @param  validation  The validation
579     *  @return The value if the validation succeeds.
580     *  @throws NullArgumentException   The validation is {@code null}.
581     *  @throws ValidationException {@code obk} failed the validation.
582     *
583     *  @since 0.1.0
584     */
585    @SuppressWarnings( "NewExceptionWithoutArguments" )
586    @API( status = STABLE, since = "0.1.0" )
587    public static final <T> T require( final T obj, final Supplier<String> messageSupplier, final Predicate<? super T> validation ) throws ValidationException
588    {
589        if( !requireNonNullArgument( validation, "validation" ).test( obj ) )
590        {
591            final var exception = nonNull( messageSupplier )
592                ? new ValidationException( messageSupplier.get() )
593                : new ValidationException();
594            throw exception;
595        }
596
597        //---* Done *----------------------------------------------------------
598        return obj;
599    }   //  require()
600
601    /**
602     *  <p>{@summary Applies the given validation on the given value, and if
603     *  that fails, a customized
604     *  {@link ValidationException}
605     *  is thrown.}</p>
606     *  <p>Unlike the method
607     *  {@link #require(Object,String,Predicate)},
608     *  this method allows to defer the creation of the message until after the
609     *  validation was performed (and failed). While this may confer a
610     *  performance advantage in the success case, some care  should be taken
611     *  that the costs the creation of the message supplier are less than the
612     *  cost of just creating the String message directly.</p>
613     *  <p>This implementation is different from
614     *  {@link #requireNonNull(Object, Supplier)}
615     *  as it takes an instance of
616     *  {@link Function}
617     *  for the {@code messageSupplier}. That function is called with
618     *  {@code obj} as the argument; this allows to add the invalid value to
619     *  the exception detail message. The provided message supplier function
620     *  must accept {@code null} as a valid argument.</p>
621     *
622     *  @param  <T> The type of the value to check.
623     *  @param  obj The value to check; can be {@code null}.
624     *  @param  messageSupplier The supplier of the detail message to be used
625     *      in the event that a {@code ValidationException} is thrown. If
626     *      {@code null} or if it returns {@code null}, no detail message is
627     *      provided.
628     *  @param  validation  The validation
629     *  @return The value if the validation succeeds.
630     *  @throws NullArgumentException   The validation is {@code null}.
631     *  @throws ValidationException {@code obj} failed the validation.
632     *
633     *  @since 0.1.0
634     */
635    @SuppressWarnings( "NewExceptionWithoutArguments" )
636    @API( status = STABLE, since = "0.1.0" )
637    public static final <T> T require( final T obj, final Function<? super T,String> messageSupplier, final Predicate<? super T> validation ) throws ValidationException
638    {
639        if( !requireNonNullArgument( validation, "validation" ).test( obj ) )
640        {
641            final var exception = nonNull( messageSupplier )
642                ? new ValidationException( messageSupplier.apply( obj ) )
643                : new NullArgumentException();
644            throw exception;
645        }
646
647        //---* Done *----------------------------------------------------------
648        return obj;
649    }   //  require()
650
651    /**
652     *  <p>{@summary Checks if the given value {@code obj} is {@code null} and
653     *  throws a
654     *  {@link NullArgumentException}
655     *  if it is {@code null}.}</p>
656     *
657     *  @param  <T> The type of the value to check.
658     *  @param  obj The value to check.
659     *  @return The value if it is not {@code null}.
660     *  @throws NullArgumentException   {@code obj} is {@code null}.
661     *
662     *  @see java.util.Objects#requireNonNull(Object)
663     *
664     *  @since 0.0.5
665     */
666    @SuppressWarnings( "NewExceptionWithoutArguments" )
667    @API( status = STABLE, since = "0.0.5" )
668    public static final <T> T requireNonNull( final T obj ) throws NullArgumentException
669    {
670        if( isNull( obj ) ) throw new NullArgumentException();
671
672        //---* Done *----------------------------------------------------------
673        return obj;
674    }   //  requireNonNull()
675
676    /**
677     *  <p>{@summary Checks if the given value {@code obj} is {@code null} and
678     *  throws a
679     *  {@link ValidationException}
680     *  with the specified message if it is {@code null}.}</p>
681     *
682     *  @param  <T> The type of the value to check.
683     *  @param  obj The value to check.
684     *  @param  message The message that is set to the thrown exception.
685     *  @return The value if it is not {@code null}.
686     *  @throws NullArgumentException   {@code message} or {@code obj} is
687     *      {@code null}.
688     *  @throws EmptyArgumentException  {@code message} is the empty String.
689     *
690     *  @see java.util.Objects#requireNonNull(Object,String)
691     *
692     *  @since 0.0.5
693     */
694    @API( status = STABLE, since = "0.0.5" )
695    public static final <T> T requireNonNull( final T obj, final String message ) throws ValidationException, NullArgumentException, EmptyArgumentException
696    {
697        requireNotEmptyArgument( message, "message" );
698        if( isNull( obj ) ) throw new ValidationException( message );
699
700        //---* Done *----------------------------------------------------------
701        return obj;
702    }   //  requireNonNull()
703
704    /**
705     *  <p>{@summary Checks that the specified object reference is not
706     *  {@code null} and throws a customized
707     *  {@link ValidationException}
708     *  if it is.}</p>
709     *  <p>Unlike the method
710     *  {@link #requireNonNull(Object,String)},
711     *  this method allows to defer the creation of the message until after the
712     *  null check failed. While this may confer a performance advantage in the
713     *  non-{@code null} case, when deciding to call this method care should be
714     *  taken that the costs of creating the message supplier are less than the
715     *  cost of just creating the String message directly.</p>
716     *
717     *  @param  <T> The type of the value to check.
718     *  @param  obj The value to check.
719     *  @param  messageSupplier The supplier of the detail message to be used
720     *      in the event that a {@code NullArgumentException} is thrown. If
721     *      {@code null}, no detail message is provided.
722     *  @return The value if it is not {@code null}.
723     *  @throws ValidationException    {@code obj} is {@code null}
724     *
725     *  @since 0.0.5
726     */
727    @API( status = STABLE, since = "0.0.5" )
728    public static final <T> T requireNonNull( final T obj, final Supplier<String> messageSupplier) throws ValidationException
729    {
730        if( isNull( obj ) )
731        {
732            final var message = nonNull( messageSupplier ) ? messageSupplier.get() : null;
733            @SuppressWarnings( "NewExceptionWithoutArguments" )
734            final var exception = isNull( message ) ? new NullArgumentException() : new ValidationException( message );
735            throw exception;
736        }
737
738        //---* Done *----------------------------------------------------------
739        return obj;
740    }   //  requireNonNull()
741
742    /**
743     *  Checks if the given argument {@code a} is {@code null} and throws a
744     *  {@link NullArgumentException}
745     *  if it is {@code null}.
746     *
747     *  @param  <T> The type of the argument to check.
748     *  @param  arg The argument to check.
749     *  @param  name    The name of the argument; this is used for the error
750     *      message.
751     *  @return The argument if it is not {@code null}.
752     *  @throws NullArgumentException   {@code arg} is {@code null}.
753     *
754     *  @since 0.0.5
755     */
756    @API( status = STABLE, since = "0.0.5" )
757    public static final <T> T requireNonNullArgument( final T arg, final String name )
758    {
759        if( isNull( name ) ) throw new NullArgumentException( "name" );
760        if( name.isEmpty() ) throw new EmptyArgumentException( "name" );
761        if( name.isBlank() ) throw new BlankArgumentException( "name" );
762        if( isNull( arg ) ) throw new NullArgumentException( name );
763
764        //---* Done *----------------------------------------------------------
765        return arg;
766    }   //  requireNonNullArgument()
767
768    /**
769     *  <p>{@summary Checks if not both of the given arguments {@code arg} and
770     *  {@code otherArg} are {@code null} and throws a
771     *  {@link NullArgumentException}
772     *  if both are {@code null}.} Otherwise, it returns {@code arg}.</p>
773     *
774     *  @param  <T> The type of the first argument to check.
775     *  @param  arg The first argument to check; it will be returned in case of
776     *      success, even if {@code null}.
777     *  @param  otherArg    The other argument to check.
778     *  @param  name    The name of the first argument; this is used for the
779     *      error message.
780     *  @param  otherName   The name of the other argument; this is used for
781     *      the error message.
782     *  @return The first argument, even that might be {@code null}.
783     *  @throws NullArgumentException   Both arguments are {@code null}.
784     *
785     *  @since 0.0.7
786     */
787    @API( status = STABLE, since = "0.0.7" )
788    public static final <T> T requireNonNullArgument( final T arg, final Object otherArg, final String name, final String otherName )
789    {
790        if( isNull( name ) ) throw new NullArgumentException( "name" );
791        if( name.isEmpty() ) throw new EmptyArgumentException( "name" );
792        if( name.isBlank() ) throw new BlankArgumentException( "name" );
793        if( isNull( otherName ) ) throw new NullArgumentException( "otherName" );
794        if( otherName.isEmpty() ) throw new EmptyArgumentException( "otherName" );
795        if( otherName.isBlank() ) throw new BlankArgumentException( "otherName" );
796        if( isNull( arg ) && isNull( otherArg ) )
797        {
798            throw new NullArgumentException( name, otherName );
799        }
800
801        //---* Done *----------------------------------------------------------
802        return arg;
803    }   //  requireNonNullArgument()
804
805    /**
806     *  <p>{@summary Checks if the given String argument {@code arg} is
807     *  {@code null}, empty or blank and throws a
808     *  {@link NullArgumentException}
809     *  if it is {@code null}, an
810     *  {@link EmptyArgumentException}
811     *  if it is empty, or a
812     *  {@link BlankArgumentException}
813     *  if it is blank.}</p>
814     *
815     *  @param  <T> The type of the argument to check.
816     *  @param  arg The argument to check; may be {@code null}.
817     *  @param  name    The name of the argument; this is used for the error
818     *      message.
819     *  @return The argument if it is not {@code null}, empty or blank.
820     *  @throws NullArgumentException   {@code arg} is {@code null}.
821     *  @throws EmptyArgumentException   {@code arg} is empty.
822     *  @throws BlankArgumentException   {@code arg} is blank.
823     *
824     *  @see    String#isBlank()
825     *
826     *  @since 0.1.0
827     */
828    @SuppressWarnings( "OverlyComplexMethod" )
829    @API( status = STABLE, since = "0.1.0" )
830    public static final <T extends CharSequence> T requireNotBlankArgument( final T arg, final String name )
831    {
832        if( isNull( name ) ) throw new NullArgumentException( "name" );
833        if( name.isEmpty() ) throw new EmptyArgumentException( "name" );
834        if( name.isBlank() ) throw new BlankArgumentException( "name" );
835
836        switch( arg )
837        {
838            case null -> throw new NullArgumentException( name );
839            case final String string ->
840            {
841                if( string.isEmpty() ) throw new EmptyArgumentException( name );
842                if( string.isBlank() ) throw new BlankArgumentException( name );
843            }
844            case final CharSequence charSequence ->
845            {
846                if( charSequence.isEmpty() ) throw new EmptyArgumentException( name );
847                if( charSequence.toString().isBlank() ) throw new BlankArgumentException( name );
848            }
849        }
850
851        //---* Done *----------------------------------------------------------
852        return arg;
853    }   //  requireNotBlankArgument()
854
855    /**
856     *  <p>{@summary Checks if the given argument {@code arg} is {@code null} or
857     *  empty and throws a
858     *  {@link NullArgumentException}
859     *  if it is {@code null}, or an
860     *  {@link EmptyArgumentException}
861     *  if it is empty.}</p>
862     *  <p>Strings, arrays, instances of
863     *  {@link java.util.Collection} and
864     *  {@link java.util.Map}
865     *  as well as instances of
866     *  {@link java.lang.StringBuilder},
867     *  {@link java.lang.StringBuffer},
868     *  and
869     *  {@link java.lang.CharSequence}
870     *  will be checked on being empty.</p>
871     *  <p>For an instance of
872     *  {@link java.util.Optional},
873     *  the presence of a value is checked in order to determine whether the
874     *  {@link Optional} is empty or not.</p>
875     *  <p>Because the interface
876     *  {@link java.util.Enumeration}
877     *  does not provide an API for the check on emptiness
878     *  ({@link java.util.Enumeration#hasMoreElements() hasMoreElements()}
879     *  will return {@code false} after all elements have been taken from
880     *  the {@code Enumeration} instance), the result for arguments of this
881     *  type has to be taken with caution.</p>
882     *  <p>For instances of
883     *  {@link java.util.stream.Stream},
884     *  this method will only check for {@code null} (like
885     *  {@link #requireNonNullArgument(Object,String)}.
886     *  This is because any operation on the stream itself would render it
887     *  unusable for later processing.</p>
888     *  <p>In case the argument is of type
889     *  {@link Optional},
890     *  this method behaves different from
891     *  {@link #requireNotEmptyArgument(Optional,String)};
892     *  this one will return the {@code Optional} instance, while the other
893     *  method will return the contents of the {@code Optional}.</p>
894     *  <p>This method will not work properly for instances of
895     *  {@link java.util.StringJoiner}, because its method
896     *  {@link java.util.StringJoiner#length() length()}
897     *  will not return 0 when a prefix, suffix, or an
898     *  &quot;{@linkplain java.util.StringJoiner#setEmptyValue(CharSequence) empty value}&quot;
899     *  was provided.</p>
900     *
901     *  @param  <T> The type of the argument to check.
902     *  @param  arg The argument to check; may be {@code null}.
903     *  @param  name    The name of the argument; this is used for the error
904     *      message.
905     *  @return The argument if it is not {@code null} or empty.
906     *  @throws NullArgumentException   {@code arg} is {@code null}.
907     *  @throws EmptyArgumentException   {@code arg} is empty.
908     *
909     *  @since 0.0.5
910     */
911    @SuppressWarnings( "OverlyComplexMethod" )
912    @API( status = STABLE, since = "0.0.5" )
913    public static final <T> T requireNotEmptyArgument( final T arg, final String name )
914    {
915        if( isNull( name ) ) throw new NullArgumentException( "name" );
916        if( name.isEmpty() ) throw new EmptyArgumentException( "name" );
917        if( name.isBlank() ) throw new BlankArgumentException( "name" );
918
919        switch( arg )
920        {
921            /*
922             * When using guarding expressions, the code would not get better
923             * to read and to understand, as the positive cases will be handled
924             * all by the default case.
925             */
926            case null -> throw new NullArgumentException( name );
927            case final CharSequence charSequence ->
928            {
929                if( charSequence.isEmpty() ) throw new EmptyArgumentException( name );
930            }
931            case final Collection<?> collection ->
932            {
933                if( collection.isEmpty() ) throw new EmptyArgumentException( name );
934            }
935            case final Map<?,?> map ->
936            {
937                if( map.isEmpty() ) throw new EmptyArgumentException( name );
938            }
939            case final Enumeration<?> enumeration ->
940            {
941                /*
942                 * The funny thing with an Enumeration is that it could have
943                 * been not empty in the beginning, but it may be empty
944                 * (= having no more elements) now.
945                 * The good thing is that Enumeration.hasMoreElements() will
946                 * not change the state of the Enumeration - at least it should
947                 * not do so.
948                 */
949                if( !enumeration.hasMoreElements() ) throw new EmptyArgumentException( name );
950            }
951            case final Optional<?> optional ->
952            {
953                /*
954                 * This is different from the behaviour of
955                 * requireNotEmptyArgument(Optional,String) as the Optional
956                 * will be returned here.
957                 */
958                if( optional.isEmpty() ) throw new EmptyArgumentException( name );
959            }
960            default ->
961            {
962                if( arg.getClass().isArray() )
963                {
964                    if( Array.getLength( arg ) == 0 ) throw new EmptyArgumentException( name );
965                }
966                else
967                {
968                    /*
969                     * Other data types are not further processed; in
970                     * particular, instances of Stream cannot be checked on
971                     * being empty. This is because any operation on the Stream
972                     * itself will change its state and may make the Stream
973                     * unusable.
974                     */
975                }
976            }
977        }
978
979        //---* Done *----------------------------------------------------------
980        return arg;
981    }   //  requireNotEmptyArgument()
982
983    /**
984     *  <p>{@summary Checks if the given argument {@code optional} of type
985     *  {@link Optional}
986     *  is {@code null} or
987     *  {@linkplain Optional#empty() empty}
988     *  and throws a
989     *  {@link NullArgumentException}
990     *  if it is {@code null}, or a
991     *  {@link EmptyArgumentException}
992     *  if it is empty.}</p>
993     *  <p>Otherwise it returns the value of the {@code Optional}.</p>
994     *  <p>This is different from the behaviour of
995     *  {@link #requireNotEmptyArgument(Object,String)}
996     *  with an instance of {@code Optional} as the argument to test.</p>
997     *
998     *  @param  <T> The type of the given {@code Optional} to check.
999     *  @param  optional    The argument to check; can be {@code null}.
1000     *  @param  name    The name of the argument; this is used for the error
1001     *      message.
1002     *  @return The value of the argument if {@code optional} is not
1003     *      {@code null}
1004     *      and not
1005     *      {@linkplain Optional#empty() empty}. This could be the empty
1006     *      string!
1007     *  @throws NullArgumentException   {@code optional} is {@code null}.
1008     *  @throws EmptyArgumentException   {@code optional} is empty.
1009     *
1010     *  @since 0.0.5
1011     */
1012    @API( status = STABLE, since = "0.0.5" )
1013    public static final <T> T requireNotEmptyArgument( @SuppressWarnings( "OptionalUsedAsFieldOrParameterType" ) final Optional<T> optional, final String name )
1014    {
1015        if( isNull( name ) ) throw new NullArgumentException( "name" );
1016        if( name.isEmpty() ) throw new EmptyArgumentException( "name" );
1017        if( name.isBlank() ) throw new BlankArgumentException( "name" );
1018
1019        //---* Check for null *------------------------------------------------
1020        if( isNull( optional ) ) throw new NullArgumentException( name );
1021        final var retValue = optional.orElseThrow( () -> new EmptyArgumentException( name ) );
1022
1023        //---* Done *----------------------------------------------------------
1024        return retValue;
1025    }   //  requireNotEmptyArgument()
1026
1027    /**
1028     *  <p>{@summary Returns the first argument if it is not {@code null},
1029     *  otherwise it returns the non-{@code null} second argument.}</p>
1030     *  <p>This implementation behaves different from that in
1031     *  {@link java.util.Objects#requireNonNullElse(Object,Object) java.util.Objects.requireNonNullElse(Object,Object)}
1032     *  as it will always check that the default is not {@code null}.</p>
1033     *
1034     *  @param <T>  The type of the references.
1035     *  @param  obj An object reference.
1036     *  @param  defaultObj  Another object reference to be returned if the
1037     *      first argument is {@code null}.
1038     *  @return The first argument if it is not {@code null}, otherwise the
1039     *      second argument if it is not {@code null}.
1040     *  @throws NullArgumentException   The {@code defaultObj} is {@code null}.
1041     *
1042     *  @see    java.util.Objects#requireNonNullElse(Object, Object)
1043     *
1044     *  @since 0.0.5
1045     */
1046    @API( status = STABLE, since = "0.0.5" )
1047    public static final <T> T requireNonNullElse( final T obj, final T defaultObj ) throws NullArgumentException
1048    {
1049        return java.util.Objects.requireNonNullElse( obj, requireNonNullArgument( defaultObj, "defaultObj" ) );
1050    }   //  requireNonNullElse()
1051
1052    /**
1053     *  <p>{@summary Returns the first argument if it is not {@code null},
1054     *  otherwise it returns the non-{@code null} value returned by
1055     *  {@link Supplier#get() supplier.get()}.}</p>
1056     *  <p>This implementation behaves different from that in
1057     *  {@link java.util.Objects#requireNonNullElseGet(Object,Supplier) java.util.Objects.requireNonNullElseGet(Object,Supplier)}
1058     *  as it will always check that the supplier is not {@code null}.</p>
1059     *
1060     *  @note   Although the provided {@code Supplier} may not be {@code null},
1061     *      it may <i>return</i> {@code null}.
1062     *
1063     *  @param <T>  The type of the reference.
1064     *  @param  obj An object reference.
1065     *  @param  supplier    The supplier of a non-{@code null} object of type
1066     *      {code T} to return if the first argument is {@code null}.
1067     *  @return The first argument if it is not {@code null}, otherwise the
1068     *      value returned by a call to {@code supplier.get()} if it is not
1069     *      {@code null}.
1070     *  @throws NullArgumentException   The {@code supplier} is {@code null}.
1071     *  @throws NullPointerException    {@code obj} is {@code null} and the
1072     *      return value of {@code supplier.get()} value is {@code null}, too.
1073     *
1074     *  @since 0.0.5
1075     */
1076    @SuppressWarnings( "ProhibitedExceptionDeclared" )
1077    @API( status = STABLE, since = "0.0.5" )
1078    public static final <T> T requireNonNullElseGet( final T obj, final Supplier<? extends T> supplier ) throws NullArgumentException, NullPointerException
1079    {
1080        return java.util.Objects.requireNonNullElseGet( obj, requireNonNullArgument( supplier, "supplier" ) );
1081    }   //  requireNonNullElseGet()
1082
1083    /**
1084     *  <p>{@summary Applies the given validation on the given value, and if
1085     *  that fails, an
1086     *  {@link ValidationException}
1087     *  with a default message is thrown.} The validation is also responsible
1088     *  for the {@code null}-check; that means, the method
1089     *  {@link Predicate#test(Object) test()}
1090     *  of the validation may be called with {@code null} as the argument.</p>
1091     *
1092     *  @param  <T> The type of the value to check.
1093     *  @param  arg The value to check; can be {@code null}.
1094     *  @param  name    The name of the argument; this is used for the error
1095     *      message.
1096     *  @param  validation  The validation
1097     *  @return The value if the validation succeeds.
1098     *  @throws ValidationException {@code arg} failed the validation.
1099     *  @throws NullArgumentException   {@code name} or {@code validation} is
1100     *      {@code null}.
1101     *  @throws EmptyArgumentException  {@code name} is the empty String.
1102     *
1103     *  @since 0.1.0
1104     */
1105    @API( status = STABLE, since = "0.1.0" )
1106    public static final <T> T requireValidArgument( final T arg, final String name, final Predicate<? super T> validation )
1107    {
1108        requireNotBlankArgument( name, "name" );
1109
1110        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1111        {
1112            throw new ValidationException( "Validation failed for '%s'".formatted( name ) );
1113        }
1114
1115        //---* Done *----------------------------------------------------------
1116        return arg;
1117    }   //  requireValidArgument()
1118
1119    /**
1120     *  <p>{@summary Applies the given validation on the given value, and if
1121     *  that fails, a
1122     *  {@link ValidationException}
1123     *  is thrown.} The message for the exception will be provided by the given
1124     *  message supplier that takes the name of the argument as an
1125     *  argument.</p>
1126     *  <p>The validation is also responsible for the {@code null}-check; that
1127     *  means, the method
1128     *  {@link Predicate#test(Object) test()}
1129     *  of the validation may be called with {@code null} as the argument.</p>
1130     *
1131     *  @param  <T> The type of the value to check.
1132     *  @param  arg The value to check; can be {@code null}.
1133     *  @param  name    The name of the argument; this is used for the error
1134     *      message.
1135     *  @param  validation  The validation
1136     *  @param  messageSupplier The function that generates the message for the
1137     *      exception.
1138     *  @return The value if the validation succeeds.
1139     *  @throws ValidationException {@code arg} failed the validation.
1140     *  @throws NullArgumentException   {@code name}, {@code validation} or
1141     *      {@code messageProvider} is {@code null}.
1142     *  @throws EmptyArgumentException  {@code name} is the empty String.
1143     *
1144     *  @since 0.1.0
1145     */
1146    @API( status = STABLE, since = "0.1.0" )
1147    public static final <T> T requireValidArgument( final T arg, final String name, final Predicate<? super T> validation, final UnaryOperator<String> messageSupplier )
1148    {
1149        requireNotBlankArgument( name, "name" );
1150        requireNonNullArgument( messageSupplier, "messageSupplier" );
1151
1152        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1153        {
1154            throw new ValidationException( messageSupplier.apply( name ) );
1155        }
1156
1157        //---* Done *----------------------------------------------------------
1158        return arg;
1159    }   //  requireValidArgument()
1160
1161    /**
1162     *  Applies the given validation on the given value, and if that fails, an
1163     *  {@link ValidationException}
1164     *  with a default message is thrown.
1165     *
1166     *  @param  arg The value to check.
1167     *  @param  name    The name of the argument; this is used for the error
1168     *      message.
1169     *  @param  validation  The validation
1170     *  @return The value if the validation succeeds.
1171     *  @throws ValidationException {@code arg} failed the validation.
1172     *  @throws NullArgumentException   {@code name} or {@code validation} is
1173     *      {@code null}.
1174     *  @throws EmptyArgumentException  {@code name} is the empty String.
1175     *
1176     *  @since 0.2.0
1177     */
1178    @API( status = STABLE, since = "0.2.0" )
1179    public static final double requireValidDoubleArgument( final double arg, final String name, final DoublePredicate validation )
1180    {
1181        requireNotBlankArgument( name, "name" );
1182
1183        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1184        {
1185            throw new ValidationException( "Validation failed for '%s'".formatted( name ) );
1186        }
1187
1188        //---* Done *----------------------------------------------------------
1189        return arg;
1190    }   //  requireValidDoubleArgument()
1191
1192    /**
1193     *  <p>{@summary Applies the given validation on the given value, and if
1194     *  that fails, a
1195     *  {@link ValidationException}
1196     *  is thrown.} The message for the exception will be provided by the given
1197     *  message supplier that takes the name of the argument as an
1198     *  argument.</p>
1199     *
1200     *  @param  arg The value to check.
1201     *  @param  name    The name of the argument; this is used for the error
1202     *      message.
1203     *  @param  validation  The validation
1204     *  @param  messageSupplier The function that generates the message for the
1205     *      exception.
1206     *  @return The value if the validation succeeds.
1207     *  @throws ValidationException {@code arg} failed the validation.
1208     *  @throws NullArgumentException   {@code name}, {@code validation} or
1209     *      {@code messageProvider} is {@code null}.
1210     *  @throws EmptyArgumentException  {@code name} is the empty String.
1211     *
1212     *  @since 0.2.0
1213     */
1214    @API( status = STABLE, since = "0.2.0" )
1215    public static final double requireValidDoubleArgument( final double arg, final String name, final DoublePredicate validation, final UnaryOperator<String> messageSupplier )
1216    {
1217        requireNotBlankArgument( name, "name" );
1218        requireNonNullArgument( messageSupplier, "messageSupplier" );
1219
1220        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1221        {
1222            throw new ValidationException( messageSupplier.apply( name ) );
1223        }
1224
1225        //---* Done *----------------------------------------------------------
1226        return arg;
1227    }   //  requireValidDoubleArgument()
1228
1229    /**
1230     *  Applies the given validation on the given value, and if that fails, an
1231     *  {@link ValidationException}
1232     *  with a default message is thrown.
1233     *
1234     *  @param  arg The value to check.
1235     *  @param  name    The name of the argument; this is used for the error
1236     *      message.
1237     *  @param  validation  The validation
1238     *  @return The value if the validation succeeds.
1239     *  @throws ValidationException {@code arg} failed the validation.
1240     *  @throws NullArgumentException   {@code name} or {@code validation} is
1241     *      {@code null}.
1242     *  @throws EmptyArgumentException  {@code name} is the empty String.
1243     *
1244     *  @since 0.2.0
1245     */
1246    @API( status = STABLE, since = "0.2.0" )
1247    public static final int requireValidIntegerArgument( final int arg, final String name, final IntPredicate validation )
1248    {
1249        requireNotBlankArgument( name, "name" );
1250
1251        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1252        {
1253            throw new ValidationException( "Validation failed for '%s'".formatted( name ) );
1254        }
1255
1256        //---* Done *----------------------------------------------------------
1257        return arg;
1258    }   //  requireValidIntegerArgument()
1259
1260    /**
1261     *  <p>{@summary Applies the given validation on the given value, and if
1262     *  that fails, a
1263     *  {@link ValidationException}
1264     *  is thrown.} The message for the exception will be provided by the given
1265     *  message supplier that takes the name of the argument as an
1266     *  argument.</p>
1267     *
1268     *  @param  arg The value to check.
1269     *  @param  name    The name of the argument; this is used for the error
1270     *      message.
1271     *  @param  validation  The validation
1272     *  @param  messageSupplier The function that generates the message for the
1273     *      exception.
1274     *  @return The value if the validation succeeds.
1275     *  @throws ValidationException {@code arg} failed the validation.
1276     *  @throws NullArgumentException   {@code name}, {@code validation} or
1277     *      {@code messageProvider} is {@code null}.
1278     *  @throws EmptyArgumentException  {@code name} is the empty String.
1279     *
1280     *  @since 0.2.0
1281     */
1282    @API( status = STABLE, since = "0.2.0" )
1283    public static final int requireValidIntegerArgument( final int arg, final String name, final IntPredicate validation, final UnaryOperator<String> messageSupplier )
1284    {
1285        requireNotBlankArgument( name, "name" );
1286        requireNonNullArgument( messageSupplier, "messageSupplier" );
1287
1288        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1289        {
1290            throw new ValidationException( messageSupplier.apply( name ) );
1291        }
1292
1293        //---* Done *----------------------------------------------------------
1294        return arg;
1295    }   //  requireValidIntegerArgument()
1296
1297    /**
1298     *  Applies the given validation on the given value, and if that fails, an
1299     *  {@link ValidationException}
1300     *  with a default message is thrown.
1301     *
1302     *  @param  arg The value to check.
1303     *  @param  name    The name of the argument; this is used for the error
1304     *      message.
1305     *  @param  validation  The validation
1306     *  @return The value if the validation succeeds.
1307     *  @throws ValidationException {@code arg} failed the validation.
1308     *  @throws NullArgumentException   {@code name} or {@code validation} is
1309     *      {@code null}.
1310     *  @throws EmptyArgumentException  {@code name} is the empty String.
1311     *
1312     *  @since 0.2.0
1313     */
1314    @API( status = STABLE, since = "0.2.0" )
1315    public static final long requireValidLongArgument( final long arg, final String name, final LongPredicate validation )
1316    {
1317        requireNotBlankArgument( name, "name" );
1318
1319        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1320        {
1321            throw new ValidationException( "Validation failed for '%s'".formatted( name ) );
1322        }
1323
1324        //---* Done *----------------------------------------------------------
1325        return arg;
1326    }   //  requireValidLongArgument()
1327
1328    /**
1329     *  <p>{@summary Applies the given validation on the given value, and if
1330     *  that fails, a
1331     *  {@link ValidationException}
1332     *  is thrown.} The message for the exception will be provided by the given
1333     *  message supplier that takes the name of the argument as an
1334     *  argument.</p>
1335     *
1336     *  @param  arg The value to check.
1337     *  @param  name    The name of the argument; this is used for the error
1338     *      message.
1339     *  @param  validation  The validation
1340     *  @param  messageSupplier The function that generates the message for the
1341     *      exception.
1342     *  @return The value if the validation succeeds.
1343     *  @throws ValidationException {@code arg} failed the validation.
1344     *  @throws NullArgumentException   {@code name}, {@code validation} or
1345     *      {@code messageProvider} is {@code null}.
1346     *  @throws EmptyArgumentException  {@code name} is the empty String.
1347     *
1348     *  @since 0.2.0
1349     */
1350    @API( status = STABLE, since = "0.2.0" )
1351    public static final long requireValidLongArgument( final long arg, final String name, final LongPredicate validation, final UnaryOperator<String> messageSupplier )
1352    {
1353        requireNotBlankArgument( name, "name" );
1354        requireNonNullArgument( messageSupplier, "messageSupplier" );
1355
1356        if( !requireNonNullArgument( validation, "validation" ).test( arg ) )
1357        {
1358            throw new ValidationException( messageSupplier.apply( name ) );
1359        }
1360
1361        //---* Done *----------------------------------------------------------
1362        return arg;
1363    }   //  requireValidLongArgument()
1364
1365    /**
1366     *  <p>{@summary Applies the given validation on the given value (that must
1367     *  not be {@code null}), and if that fails, an
1368     *  {@link ValidationException}
1369     *  with a default message is thrown.}</p>
1370     *  <p>If the value is {@code null}, the validation is never triggered.</p>
1371     *
1372     *  @param  <T> The type of the value to check.
1373     *  @param  arg The value to check.
1374     *  @param  name    The name of the argument; this is used for the error
1375     *      message.
1376     *  @param  validation  The validation
1377     *  @return The value if the validation succeeds.
1378     *  @throws ValidationException {@code a} failed the validation.
1379     *  @throws NullArgumentException   {@code arg}, {@code name} or
1380     *      {@code validation} is {@code null}.
1381     *  @throws EmptyArgumentException  {@code name} is the empty String.
1382     *
1383     *  @since 0.1.0
1384     */
1385    @API( status = STABLE, since = "0.1.0" )
1386    public static final <T> T requireValidNonNullArgument( final T arg, final String name, final Predicate<? super T> validation )
1387    {
1388        requireNotBlankArgument( name, "name" );
1389
1390        if( !requireNonNullArgument( validation, "validation" ).test( requireNonNullArgument( arg, "name" ) ) )
1391        {
1392            throw new ValidationException( "Validation failed for '%s'".formatted( name ) );
1393        }
1394
1395        //---* Done *----------------------------------------------------------
1396        return arg;
1397    }   //  requireValidNonNullArgument()
1398
1399    /**
1400     *  <p>{@summary Applies the given validation on the given value (that must
1401     *  not be {@code null}), and if that fails, a
1402     *  {@link ValidationException}
1403     *  is thrown.} The message for the exception will be provided by the given
1404     *  message supplier that takes the name of the argument as an
1405     *  argument.</p>
1406     *
1407     *  @param  <T> The type of the value to check.
1408     *  @param  arg The value to check.
1409     *  @param  name    The name of the argument; this is used for the error
1410     *      message.
1411     *  @param  validation  The validation
1412     *  @param  messageSupplier The function that generates the message for the
1413     *      exception.
1414     *  @return The value if the validation succeeds.
1415     *  @throws ValidationException {@code arg} failed the validation.
1416     *  @throws NullArgumentException   {@code arg}, {@code name},
1417     *      {@code validation} or {@code messageProvider} is {@code null}.
1418     *  @throws EmptyArgumentException  {@code name} is the empty String.
1419     *
1420     *  @since 0.1.0
1421     */
1422    @API( status = STABLE, since = "0.1.0" )
1423    public static final <T> T requireValidNonNullArgument( final T arg, final String name, final Predicate<? super T> validation, final UnaryOperator<String> messageSupplier )
1424    {
1425        requireNotBlankArgument( name, "name" );
1426        requireNonNullArgument( messageSupplier, "messageSupplier" );
1427
1428        if( !requireNonNullArgument( validation, "validation" ).test( requireNonNullArgument( arg, "name" ) ) )
1429        {
1430            throw new ValidationException( messageSupplier.apply( name ) );
1431        }
1432
1433        //---* Done *----------------------------------------------------------
1434        return arg;
1435    }   //  requireValidNonNullArgument()
1436
1437    /**
1438     *  <p>{@summary Converts the given argument {@code object} into a
1439     *  {@link String},
1440     *  usually by calling its
1441     *  {@link Object#toString() toString()}
1442     *  method.} If the value of the argument is {@code null}, the text
1443     *  &quot;{@link org.tquadrat.foundation.lang.CommonConstants#NULL_STRING null}&quot;
1444     *  will be returned instead. Arrays will be converted to a String through
1445     *  calling the respective {@code toString()} method from
1446     *  {@link java.util.Arrays}
1447     *  (this distinguishes this implementation from
1448     *  {link java.util.Objects#toString(Object, String) java.util.Objects.toString()}).
1449     *  Values of type
1450     *  {@link java.util.Date} or
1451     *  {@link java.util.Calendar}
1452     *  will be translated based on the default locale - whatever that is.
1453     *
1454     *  @param  object  The object; may be {@code null}.
1455     *  @return The object's string representation.
1456     *
1457     *  @see java.util.Arrays#toString(boolean[])
1458     *  @see java.util.Arrays#toString(byte[])
1459     *  @see java.util.Arrays#toString(char[])
1460     *  @see java.util.Arrays#toString(double[])
1461     *  @see java.util.Arrays#toString(float[])
1462     *  @see java.util.Arrays#toString(int[])
1463     *  @see java.util.Arrays#toString(long[])
1464     *  @see java.util.Arrays#toString(Object[])
1465     *  @see java.util.Arrays#toString(short[])
1466     *  @see java.util.Arrays#deepToString(Object[])
1467     *  @see java.util.Locale#getDefault()
1468     *  @see org.tquadrat.foundation.lang.CommonConstants#NULL_STRING
1469     *
1470     *  @since 0.0.5
1471     */
1472    @API( status = STABLE, since = "0.0.5" )
1473    public static final String toString( final Object object )
1474    {
1475        return toString( object, NULL_STRING );
1476    }   //  toString()
1477
1478    /**
1479     *  <p>{@summary Converts the given argument {@code object} into a
1480     *  {@link String},
1481     *  usually by calling its
1482     *  {@link Object#toString() toString()}
1483     *  method.} If the value of the argument is {@code null}, the text
1484     *  provided as the {@code nullDefault} argument will be returned
1485     *  instead.</p>
1486     *  <p>Arrays will be converted to a string through calling the respective
1487     *  {@code toString()} method from
1488     *  {@link java.util.Arrays}
1489     *  (this distinguishes this implementation from
1490     *  {link java.util.Objects#toString(Object,String) java.util.Objects.toString(Object,String)}).</p>
1491     *  <p>Values of type
1492     *  {@link java.util.Date} or
1493     *  {@link java.util.Calendar}
1494     *  will be translated based on the
1495     *  {@link java.util.Locale#getDefault() default locale}
1496     *  – whatever that is.</p>
1497     *
1498     *  @param  object  The object; may be {@code null}.
1499     *  @param  nullDefault The text that should be returned if {@code object}
1500     *      is {@code null}.
1501     *  @return The object's string representation.
1502     *
1503     *  @see java.util.Arrays#toString(boolean[])
1504     *  @see java.util.Arrays#toString(byte[])
1505     *  @see java.util.Arrays#toString(char[])
1506     *  @see java.util.Arrays#toString(double[])
1507     *  @see java.util.Arrays#toString(float[])
1508     *  @see java.util.Arrays#toString(int[])
1509     *  @see java.util.Arrays#toString(long[])
1510     *  @see java.util.Arrays#toString(Object[])
1511     *  @see java.util.Arrays#toString(short[])
1512     *  @see java.util.Arrays#deepToString(Object[])
1513     *  @see java.util.Locale#getDefault()
1514     *
1515     *  @since 0.0.5
1516     */
1517    @SuppressWarnings( {"IfStatementWithTooManyBranches", "ChainOfInstanceofChecks", "OverlyComplexMethod"} )
1518    @API( status = STABLE, since = "0.0.5" )
1519    public static final String toString( final Object object, final String nullDefault )
1520    {
1521        var retValue = requireNonNullArgument( nullDefault, "nullDefault" );
1522        if( nonNull( object ) )
1523        {
1524            final var objectClass = object.getClass();
1525            if( objectClass.isArray() )
1526            {
1527                if( objectClass == byte [].class )
1528                {
1529                    retValue = Arrays.toString( (byte []) object );
1530                }
1531                else if( objectClass == short [].class )
1532                {
1533                    retValue = Arrays.toString( (short []) object );
1534                }
1535                else if( objectClass == int [].class )
1536                {
1537                    retValue = Arrays.toString( (int []) object );
1538                }
1539                else if( objectClass == long [].class )
1540                {
1541                    retValue = Arrays.toString( (long []) object );
1542                }
1543                else if( objectClass == char [].class )
1544                {
1545                    retValue = Arrays.toString( (char []) object );
1546                }
1547                else if( objectClass == float [].class )
1548                {
1549                    retValue = Arrays.toString( (float []) object );
1550                }
1551                else if( objectClass == double [].class )
1552                {
1553                    retValue = Arrays.toString( (double []) object );
1554                }
1555                else if( objectClass == boolean [].class )
1556                {
1557                    retValue = Arrays.toString( (boolean []) object );
1558                }
1559                else
1560                {
1561                    retValue = deepToString( (Object []) object );
1562                }
1563            }
1564            else
1565            {
1566                retValue = object.toString();
1567            }
1568        }
1569
1570        //---* Done *----------------------------------------------------------
1571        return retValue;
1572    }   //  toString()
1573
1574    /**
1575     *  <p>{@summary Converts the given argument into a
1576     *  {@link String}
1577     *  using the given instance of
1578     *  {@link Stringer}.}
1579     *  If the value of the argument is {@code null}, the text
1580     *  provided as the {@code nullDefault} argument will be returned
1581     *  instead.</p>
1582     *
1583     *  @param  <T> The type of the object.
1584     *  @param  value   The object; may be {@code null}.
1585     *  @param  stringer    The method that is used to convert the given object
1586     *      to a String.
1587     *  @param  nullDefault The text that should be returned if {@code object}
1588     *      is {@code null}.
1589     *  @return The object's string representation.
1590     *
1591     *  @see    Stringer
1592     *
1593     *  @since 0.0.5
1594     */
1595    @API( status = STABLE, since = "0.0.5" )
1596    public static final <T> String toString( final T value, final Stringer<? super T> stringer, final String nullDefault )
1597    {
1598        requireNonNullArgument( nullDefault, "nullDefault" );
1599
1600        final var retValue = nonNull( value ) ? requireNonNullArgument( stringer, "stringer" ).toString( value ) : nullDefault;
1601
1602        //---* Done *----------------------------------------------------------
1603        return retValue;
1604    }   //  toString()
1605}
1606//  class Objects
1607
1608/*
1609 *  End of File
1610 */