001package org.apache.juneau.commons.utils;
002
003import static org.apache.juneau.commons.utils.Exceptions.*;
004import static org.apache.juneau.commons.utils.ObjectUtils.*;
005import static org.apache.juneau.commons.utils.Shorts.nn;
006import static org.apache.juneau.commons.utils.Shorts.req;
007import static org.apache.juneau.commons.utils.Shorts.reqnn;
008
009import java.lang.reflect.*;
010import java.util.*;
011import java.util.function.*;
012import java.util.stream.*;
013
014import org.apache.juneau.commons.collections.*;
015
016/*
017 * Licensed to the Apache Software Foundation (ASF) under one or more
018 * contributor license agreements.  See the NOTICE file distributed with
019 * this work for additional information regarding copyright ownership.
020 * The ASF licenses this file to You under the Apache License, Version 2.0
021 * (the "License"); you may not use this file except in compliance with
022 * the License.  You may obtain a copy of the License at
023 *
024 *      http://www.apache.org/licenses/LICENSE-2.0
025 *
026 * Unless required by applicable law or agreed to in writing, software
027 * distributed under the License is distributed on an "AS IS" BASIS,
028 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
029 * See the License for the specific language governing permissions and
030 * limitations under the License.
031 */
032
033/**
034 * Utility methods for working with collections and maps.
035 *
036 * <h5 class='section'>Complex Data Structure Construction:</h5>
037 * <p>
038 * This class provides convenient shorthand methods for creating complex nested data structures.
039 * The primary methods for building structures are:
040 * <ul>
041 *    <li>{@link #array(Object...)} - Creates arrays
042 *    <li>{@link #objectArray(Object...)} - Creates Object arrays (when type inference needs help)
043 *    <li>{@link #list(Object...)} / {@link #fixedSizeList(Object...)} - Creates modifiable lists
044 *    <li>{@link #map(Object, Object, Object, Object, Object, Object)} - Creates modifiable maps
045 *    <li>{@link #immutableMap(Object, Object, Object, Object, Object, Object)} - Creates unmodifiable maps
046 * </ul>
047 *
048 * <h5 class='section'>Examples:</h5>
049 * <p class='bjava'>
050 *    <jc>// Array of lists of maps</jc>
051 *    <jk>var</jk> <jv>data</jv> = <jsm>a</jsm>(
052 *       <jsm>l</jsm>(<jsm>m</jsm>(<js>"name"</js>, <js>"John"</js>, <js>"age"</js>, 30)),
053 *       <jsm>l</jsm>(<jsm>m</jsm>(<js>"name"</js>, <js>"Jane"</js>, <js>"age"</js>, 25))
054 *    );
055 *
056 *    <jc>// Compare with traditional Java syntax:</jc>
057 *    List&lt;Map&lt;String,Object&gt;&gt;[] <jv>data</jv> = <jk>new</jk> List[]{
058 *       <jk>new</jk> ArrayList&lt;&gt;(Arrays.asList(
059 *          <jk>new</jk> LinkedHashMap&lt;&gt;(){{
060 *             put(<js>"name"</js>, <js>"John"</js>);
061 *             put(<js>"age"</js>, 30);
062 *          }}
063 *       )),
064 *       <jk>new</jk> ArrayList&lt;&gt;(Arrays.asList(
065 *          <jk>new</jk> LinkedHashMap&lt;&gt;(){{
066 *             put(<js>"name"</js>, <js>"Jane"</js>);
067 *             put(<js>"age"</js>, 25);
068 *          }}
069 *       ))
070 *    };
071 * </p>
072 *
073 * <p class='bjava'>
074 *    <jc>// Complex nested structure: Array of lists containing maps and arrays</jc>
075 *    <jk>var</jk> <jv>complex</jv> = <jsm>a</jsm>(
076 *       <jsm>l</jsm>(
077 *          <jsm>m</jsm>(<js>"user"</js>, <js>"admin"</js>, <js>"roles"</js>, <jsm>a</jsm>(<js>"read"</js>, <js>"write"</js>, <js>"delete"</js>)),
078 *          <jsm>m</jsm>(<js>"user"</js>, <js>"guest"</js>, <js>"roles"</js>, <jsm>a</jsm>(<js>"read"</js>))
079 *       ),
080 *       <jsm>l</jsm>(
081 *          <jsm>m</jsm>(<js>"status"</js>, <js>"active"</js>, <js>"count"</js>, 42)
082 *       )
083 *    );
084 *
085 *    <jc>// Traditional Java equivalent (significantly more verbose):</jc>
086 *    List&lt;Map&lt;String,Object&gt;&gt;[] <jv>complex</jv> = <jk>new</jk> List[]{
087 *       <jk>new</jk> ArrayList&lt;&gt;(Arrays.asList(
088 *          <jk>new</jk> LinkedHashMap&lt;&gt;(){{
089 *             put(<js>"user"</js>, <js>"admin"</js>);
090 *             put(<js>"roles"</js>, <jk>new</jk> String[]{<js>"read"</js>, <js>"write"</js>, <js>"delete"</js>});
091 *          }},
092 *          <jk>new</jk> LinkedHashMap&lt;&gt;(){{
093 *             put(<js>"user"</js>, <js>"guest"</js>);
094 *             put(<js>"roles"</js>, <jk>new</jk> String[]{<js>"read"</js>});
095 *          }}
096 *       )),
097 *       <jk>new</jk> ArrayList&lt;&gt;(Arrays.asList(
098 *          <jk>new</jk> LinkedHashMap&lt;&gt;(){{
099 *             put(<js>"status"</js>, <js>"active"</js>);
100 *             put(<js>"count"</js>, 42);
101 *          }}
102 *       ))
103 *    };
104 * </p>
105 *
106 * <p class='bjava'>
107 *    <jc>// Using unmodifiable maps for immutable data</jc>
108 *    <jk>var</jk> <jv>config</jv> = <jsm>a</jsm>(
109 *       <jsm>m</jsm>(<js>"env"</js>, <js>"production"</js>, <js>"debug"</js>, <jk>false</jk>),
110 *       <jsm>m</jsm>(<js>"env"</js>, <js>"development"</js>, <js>"debug"</js>, <jk>true</jk>)
111 *    );
112 * </p>
113 *
114 * <h5 class='section'>Best Practices:</h5>
115 * <ul>
116 *    <li>Use {@link #array(Object...)} for arrays when type can be inferred, {@link #objectArray(Object...)} for Object arrays
117 *    <li>Use {@link #map(Object, Object, Object, Object, Object, Object)} when you need modifiable maps
118 *    <li>Use {@link #immutableMap(Object, Object, Object, Object, Object, Object)} when you need immutable/unmodifiable maps
119 *    <li>Use {@link #list(Object...)} or {@link #fixedSizeList(Object...)} for modifiable lists
120 *    <li>Static import these methods for maximum readability: <code>import static org.apache.juneau.commons.utils.CollectionUtils.*;</code>
121 * </ul>
122 *
123 * <h5 class='section'>See Also:</h5><ul>
124 *    <li class='link'><a class="doclink" href="../../../../../index.html#juneau-commons">juneau-commons</a>
125 * </ul>
126 */
127@SuppressWarnings({
128   "java:S107", // Many parameters acceptable for convenience method
129   "java:S1168", // nullList/nullMap/toList(nullIfEmpty) deliberately return null as the documented "absent" value
130   "java:S1172", // nullList/nullMap take Class parameters solely to drive generic type inference at call sites
131   "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants
132   "java:S6539", // Monster class; CollectionUtils is intentionally a single cohesive collection-utility hub, not a set of unrelated responsibilities
133   "rawtypes", // copyArrayToList() exposes a raw List (public API) and sortedList() sorts via raw Comparable
134   "unchecked" // Generic-array cast in combine() and raw Comparable sort in sortedList() are safe: elements are only read/compared as Object/Comparable
135})
136public class CollectionUtils {
137
138   /**
139    * Traverses all elements in the specified objects and accumulates them into a list.
140    *
141    * <p>
142    * Input shapes are processed as follows:
143    * <ul>
144    *    <li><b>Flattened (recursively):</b> {@link Iterable}, {@link Stream}, and any array type (including all 8 primitive
145    *       array types via {@link ClassUtils#isArray}), including arbitrary nesting and mixing of these
146    *       (e.g. a {@code List<int[]>}, an array of {@code Stream}s, etc.).
147    *    <li><b>Leaf (added as-is):</b> anything else — {@link String}, {@link Map}, custom beans, boxed primitives, etc.
148    *    <li><b>{@code null} handling:</b> a {@code null} root, or {@code null} encountered mid-traversal, contributes nothing
149    *       to the result — not even a {@code null} element.
150    * </ul>
151    *
152    * <h5 class='section'>Example:</h5>
153    * <p class='bjava'>
154    *    List&lt;Object&gt; <jv>nested</jv> = List.of(<jk>new</jk> <jk>int</jk>[]{1, 2}, List.of(<js>"a"</js>, <js>"b"</js>));
155    *
156    *    <jc>// Returns [1, 2, "a", "b"]</jc>
157    *    List&lt;Object&gt; <jv>result</jv> = <jsm>accumulate</jsm>(<jv>nested</jv>);
158    *
159    *    <jc>// Multi-root: returns [1, 2, "a", "b"]</jc>
160    *    List&lt;Object&gt; <jv>result2</jv> = <jsm>accumulate</jsm>(<jk>new</jk> <jk>int</jk>[]{1, 2}, <js>"a"</js>, <js>"b"</js>);
161    * </p>
162    *
163    * @param <T> The element type.
164    * @param o The objects to traverse. Can be <jk>null</jk> or empty, in which case an empty list is returned.
165    * @return A new modifiable list containing all accumulated leaf elements.
166    */
167   public static <T> List<T> accumulate(Object... o) {
168      var l = list();
169      if (o != null)
170         for (var x : o)
171            traverse(x, l::add);
172      return (List<T>)l;
173   }
174
175   /**
176    * Traverses all elements in the specified objects and returns them as a lazily-evaluated stream,
177    * without building an intermediate list.
178    *
179    * <p>
180    * Accepts the same input shapes as {@link #accumulate(Object...)} — see that method's Javadoc for the full
181    * list of flattened vs. leaf types and null-handling semantics.
182    *
183    * <p>
184    * Named {@code deepStream} rather than {@code stream} to avoid an erasure conflict with the existing
185    * shallow-array overload {@link #stream(Object[])}, which has the same erased parameter type ({@code Object[]}).
186    *
187    * <h5 class='section'>Example:</h5>
188    * <p class='bjava'>
189    *    List&lt;Object&gt; <jv>nested</jv> = List.of(<jk>new</jk> <jk>int</jk>[]{1, 2}, List.of(<js>"a"</js>, <js>"b"</js>));
190    *
191    *    <jc>// Lazily yields 1, 2, "a", "b"</jc>
192    *    <jsm>deepStream</jsm>(<jv>nested</jv>).forEach(System.<jk>out</jk>::println);
193    * </p>
194    *
195    * @param <T> The element type.
196    * @param o The objects to traverse. Can be <jk>null</jk> or empty, in which case an empty stream is returned.
197    * @return A lazily-evaluated stream of all leaf elements.
198    */
199   public static <T> Stream<T> deepStream(Object... o) {
200      if (o == null)
201         return Stream.empty();
202      return Arrays.stream(o).flatMap(CollectionUtils::traverseToStream);
203   }
204
205   /**
206    * Adds all the specified values to the specified collection.
207    * Creates a new set if the value is <jk>null</jk>.
208    *
209    * @param <E> The element type.
210    * @param value The collection to add to.  Can be <jk>null</jk> (a new list is created and returned).
211    * @param entries The entries to add.  Can be <jk>null</jk> (treated as a no-op — the value is returned unchanged).
212    * @return The set.
213    */
214   @SafeVarargs
215   public static <E> List<E> addAll(List<E> value, E...entries) {
216      if (isNotNull(entries)) {
217         if (value == null)
218            value = list(entries);
219         else
220            Collections.addAll(value, entries);
221      }
222      return value;
223   }
224
225   /**
226    * Adds all the specified values to the specified collection.
227    * Creates a new set if the value is <jk>null</jk>.
228    *
229    * @param <E> The element type.
230    * @param value The collection to add to.  Can be <jk>null</jk> (a new list is created and returned).
231    * @param entries The entries to add.  Can be <jk>null</jk> (treated as a no-op — the value is returned unchanged).
232    * @return The set.
233    */
234   public static <E> List<E> addAll(List<E> value, List<E> entries) {
235      if (isNotNull(entries)) {
236         if (value == null)
237            value = new ArrayList<>(entries);
238         else
239            value.addAll(entries);
240      }
241      return value;
242   }
243
244   /**
245    * Adds all the specified values to the specified collection.
246    * Creates a new set if the value is <jk>null</jk>.
247    *
248    * @param <E> The element type.
249    * @param value The collection to add to.  Can be <jk>null</jk> (a new set is created and returned).
250    * @param entries The entries to add.  Can be <jk>null</jk> (treated as a no-op — the value is returned unchanged).
251    * @return The set.
252    */
253   @SafeVarargs
254   public static <E> Set<E> addAll(Set<E> value, E...entries) {
255      if (isNotNull(entries)) {
256         if (value == null)
257            value = set(entries);
258         else
259            Collections.addAll(value, entries);
260      }
261      return value;
262   }
263
264   /**
265    * Adds all the specified values to the specified collection.
266    * Creates a new set if the value is <jk>null</jk>.
267    *
268    * @param <E> The element type.
269    * @param value The collection to add to.  Can be <jk>null</jk> (a new sorted set is created and returned).
270    * @param entries The entries to add.  Can be <jk>null</jk> (treated as a no-op — the value is returned unchanged).
271    * @return The set.
272    */
273   @SafeVarargs
274   public static <E> SortedSet<E> addAll(SortedSet<E> value, E...entries) {
275      if (isNotNull(entries)) {
276         if (value == null)
277            value = sortedSet(entries);
278         else
279            Collections.addAll(value, entries);
280      }
281      return value;
282   }
283
284   /**
285    * Adds all non-<jk>null</jk> entries to the specified collection.
286    *
287    * <p>
288    * <jk>null</jk> elements are skipped.
289    * A <jk>null</jk> entries array is a no-op.
290    *
291    * <h5 class='section'>Example:</h5>
292    * <p class='bjava'>
293    *    List&lt;String&gt; <jv>list</jv> = <jk>new</jk> ArrayList&lt;&gt;();
294    *    addAllNn(<jv>list</jv>, <js>"a"</js>, <jk>null</jk>, <js>"b"</js>);  <jc>// list is [a, b]</jc>
295    * </p>
296    *
297    * @param <E> The element type.
298    * @param <C> The collection type.
299    * @param value The collection to add to.  Must not be <jk>null</jk>.
300    * @param entries The entries to add.  Can be <jk>null</jk> (no-op); <jk>null</jk> elements are skipped.
301    * @return The same collection instance that was passed in.
302    */
303   @SafeVarargs
304   public static <E, C extends Collection<? super E>> C addAllNn(C value, E...entries) {
305      if (nn(entries))
306         for (var e : entries)
307            if (nn(e))
308               value.add(e);
309      return value;
310   }
311
312   /**
313    * Adds all non-<jk>null</jk> elements of the specified collection to the specified target collection.
314    *
315    * <p>
316    * <jk>null</jk> elements are skipped.
317    * A <jk>null</jk> entries collection is a no-op.
318    *
319    * <h5 class='section'>Example:</h5>
320    * <p class='bjava'>
321    *    Set&lt;String&gt; <jv>set</jv> = <jk>new</jk> LinkedHashSet&lt;&gt;();
322    *    addAllNn(<jv>set</jv>, Arrays.<jsm>asList</jsm>(<js>"a"</js>, <jk>null</jk>, <js>"b"</js>));  <jc>// set is [a, b]</jc>
323    * </p>
324    *
325    * @param <E> The element type.
326    * @param <C> The collection type.
327    * @param value The collection to add to.  Must not be <jk>null</jk>.
328    * @param entries The entries to add.  Can be <jk>null</jk> (no-op); <jk>null</jk> elements are skipped.
329    * @return The same collection instance that was passed in.
330    */
331   public static <E, C extends Collection<? super E>> C addAllNn(C value, Collection<? extends E> entries) {
332      if (nn(entries))
333         for (var e : entries)
334            if (nn(e))
335               value.add(e);
336      return value;
337   }
338
339   /**
340    * Appends one or more elements to an array.
341    *
342    * @param <T> The element type.
343    * @param array The array to append to.  Can be <jk>null</jk> (the new elements are returned as-is).
344    * @param newElements The new elements to append to the array.  Must not be <jk>null</jk>; if empty, the original array is returned.
345    * @return A new array with the specified elements appended.
346    */
347   public static <T> T[] addAll(T[] array, T...newElements) {
348      if (array == null)
349         return newElements;
350      if (newElements.length == 0)
351         return array;
352      var a = (T[])Array.newInstance(array.getClass().getComponentType(), array.length + newElements.length);
353      System.arraycopy(array, 0, a, 0, array.length);
354      System.arraycopy(newElements, 0, a, array.length, newElements.length);
355      return a;
356   }
357
358   /**
359    * Creates an array of the specified component type and length.
360    *
361    * @param <E> The component type of the array.
362    * @param componentType The component type of the array.  Must not be <jk>null</jk>.
363    * @param length The length of the array.
364    * @return A new array of the specified type and length. Never <jk>null</jk>.
365    */
366   public static <E> E[] array(Class<E> componentType, int length) {
367      return (E[])Array.newInstance(componentType, length);
368   }
369
370   /**
371    * Converts the specified collection to an array.
372    *
373    * @param <E> The element type.
374    * @param value The collection to convert.  Must not be <jk>null</jk> (a <jk>null</jk> argument throws {@link IllegalArgumentException}).
375    * @param componentType The component type of the array.  Must not be <jk>null</jk>.
376    * @return A new array.
377    */
378   public static <E> E[] array(Collection<E> value, Class<E> componentType) {
379      reqnn("value", value);
380      var array = (E[])Array.newInstance(componentType, value.size());
381      return value.toArray(array);
382   }
383
384   /**
385    * Converts any array (including primitive arrays) to a List.
386    *
387    * @param array The array to convert. Can be any array type including primitives.  Must not be <jk>null</jk> (a <jk>null</jk> argument throws {@link IllegalArgumentException}).
388    * @return A List containing the array elements. Primitive values are auto-boxed.  Never <jk>null</jk>.
389    * @throws IllegalArgumentException if the input is <jk>null</jk> or is not an array.
390    */
391   @SuppressWarnings({
392      "java:S3776" // Cognitive complexity acceptable for array conversion
393   })
394   public static List<Object> arrayToList(Object array) {
395      reqnn("array", array);
396      req(ClassUtils.isArray(array), "Input must be an array but was %s", ClassUtils.className(array));
397
398      var componentType = array.getClass().getComponentType();
399      var length = Array.getLength(array);
400      var result = new ArrayList<>(length);
401
402      // Handle primitive arrays specifically for better performance
403      if (componentType.isPrimitive()) {
404         if (componentType == int.class) {
405            var arr = (int[])array;
406            for (var value : arr) {
407               result.add(value);
408            }
409         } else if (componentType == long.class) {
410            var arr = (long[])array;
411            for (var value : arr) {
412               result.add(value);
413            }
414         } else if (componentType == double.class) {
415            var arr = (double[])array;
416            for (var value : arr) {
417               result.add(value);
418            }
419         } else if (componentType == float.class) {
420            var arr = (float[])array;
421            for (var value : arr) {
422               result.add(value);
423            }
424         } else if (componentType == boolean.class) {
425            var arr = (boolean[])array;
426            for (var value : arr) {
427               result.add(value);
428            }
429         } else if (componentType == byte.class) {
430            var arr = (byte[])array;
431            for (var value : arr) {
432               result.add(value);
433            }
434         } else if (componentType == char.class) {
435            var arr = (char[])array;
436            for (var value : arr) {
437               result.add(value);
438            }
439         } else /* (componentType == short.class) */ {
440            var arr = (short[])array;
441            for (var value : arr) {
442               result.add(value);
443            }
444         }
445      } else {
446         // Handle Object arrays
447         for (var i = 0; i < length; i++) {
448            result.add(Array.get(array, i));
449         }
450      }
451
452      return result;
453   }
454
455   /**
456    * Combine an arbitrary number of arrays into a single array.
457    *
458    * @param <E> The element type.
459    * @param arrays Collection of arrays to combine.  Must not be <jk>null</jk> (a <jk>null</jk> array argument throws {@link IllegalArgumentException}); individual <jk>null</jk> array entries are skipped.
460    * @return A new combined array, or an empty array if all arrays are <jk>null</jk>.
461    */
462   public static <E> E[] combine(E[]...arrays) {
463      reqnn("arrays", arrays);
464      int l = 0;
465      E[] a1 = null;
466      for (var a : arrays) {
467         if (a1 == null && isNotNull(a))
468            a1 = a;
469         l += (a == null ? 0 : a.length);
470      }
471      if (a1 == null)
472         return (E[]) new Object[0];
473      var a = (E[])Array.newInstance(a1.getClass().getComponentType(), l);
474      int i = 0;
475      for (var aa : arrays)
476         if (isNotNull(aa))
477            for (var t : aa)
478               a[i++] = t;
479      return a;
480   }
481
482   /**
483    * Returns <jk>true</jk> if the specified array contains the specified element using the {@link String#equals(Object)}
484    * method.
485    *
486    * @param element The element to check for.
487    * @param array The array to check.
488    * @return
489    *    <jk>true</jk> if the specified array contains the specified element,
490    *    <jk>false</jk> if the array or element is <jk>null</jk>.
491    */
492   public static <T> boolean contains(T element, T[] array) {
493      return indexOf(element, array) != -1;
494   }
495
496   /**
497    * Copies the specified array into the specified list.
498    *
499    * <p>
500    * Works on both object and primitive arrays.
501    *
502    * @param array The array to copy into a list.  Can be <jk>null</jk> (nothing is copied).
503    * @param list The list to copy the values into.  Must not be <jk>null</jk> when the array is non-<jk>null</jk>.
504    * @return The same list passed in.
505    */
506   public static List copyArrayToList(Object array, List list) {
507      if (isNotNull(array)) {
508         var length = Array.getLength(array);
509         for (var i = 0; i < length; i++)
510            list.add(Array.get(array, i));
511      }
512      return list;
513   }
514
515   /**
516    * Returns the next value from an iterator, or an empty Optional if there are no more elements.
517    *
518    * <p>
519    * This is a null-safe operation. Returns an empty Optional if the iterator is <jk>null</jk> or
520    * has no more elements.
521    *
522    * <h5 class='section'>Example:</h5>
523    * <p class='bjava'>
524    *    Iterator&lt;String&gt; <jv>it</jv> = list.iterator();
525    *    Optional&lt;String&gt; <jv>first</jv> = <jsm>next</jsm>(<jv>it</jv>);  <jc>// Optional.of("first")</jc>
526    *    Optional&lt;String&gt; <jv>second</jv> = <jsm>next</jsm>(<jv>it</jv>);  <jc>// Optional.of("second")</jc>
527    *    Optional&lt;String&gt; <jv>empty</jv> = <jsm>next</jsm>(<jv>it</jv>);   <jc>// Optional.empty()</jc>
528    *    Optional&lt;String&gt; <jv>nullResult</jv> = <jsm>next</jsm>(<jk>null</jk>);  <jc>// Optional.empty()</jc>
529    * </p>
530    *
531    * @param <E> The element type.
532    * @param iterator The iterator. Can be <jk>null</jk>.
533    * @return An Optional containing the next element, or empty if the iterator is <jk>null</jk> or has no more elements.
534    */
535   public static <E> Optional<E> next(Iterator<? extends E> iterator) {
536      if (iterator == null || !iterator.hasNext())
537         return emptyOptional();
538      return optional(iterator.next());
539   }
540
541   /**
542    * Returns the first element in an iterable.
543    *
544    * <p>
545    * This is a null-safe operation. Returns an empty Optional if the iterable is <jk>null</jk> or empty.
546    *
547    * <h5 class='section'>Example:</h5>
548    * <p class='bjava'>
549    *    List&lt;String&gt; <jv>list</jv> = <jsm>l</jsm>(<js>"a"</js>, <js>"b"</js>, <js>"c"</js>);
550    *    Optional&lt;String&gt; <jv>first</jv> = <jsm>first</jsm>(<jv>list</jv>);  <jc>// Optional.of("a")</jc>
551    *
552    *    Set&lt;Integer&gt; <jv>set</jv> = <jsm>s</jsm>(1, 2, 3);
553    *    Optional&lt;Integer&gt; <jv>firstInt</jv> = <jsm>first</jsm>(<jv>set</jv>);  <jc>// Optional.of(1) or another element</jc>
554    *
555    *    EnumSet&lt;MyEnum&gt; <jv>enumSet</jv> = EnumSet.allOf(MyEnum.<jk>class</jk>);
556    *    Optional&lt;MyEnum&gt; <jv>firstEnum</jv> = <jsm>first</jsm>(<jv>enumSet</jv>);  <jc>// Optional.of(first enum value)</jc>
557    *
558    *    Optional&lt;String&gt; <jv>empty</jv> = <jsm>first</jsm>(Collections.emptyList());  <jc>// Optional.empty()</jc>
559    *    Optional&lt;String&gt; <jv>nullResult</jv> = <jsm>first</jsm>(<jk>null</jk>);  <jc>// Optional.empty()</jc>
560    * </p>
561    *
562    * @param <E> The element type.
563    * @param iterable The iterable. Can be <jk>null</jk>.
564    * @return An Optional containing the first element, or empty if the iterable is <jk>null</jk> or empty.
565    */
566   public static <E> Optional<E> first(Iterable<? extends E> iterable) {
567      if (iterable == null)
568         return emptyOptional();
569      Iterator<? extends E> iterator = iterable.iterator();
570      return next(iterator);
571   }
572
573   /**
574    * Iterates the specified array in reverse order.
575    *
576    * @param <E> The element type.
577    * @param value The array to iterate.  Must not be <jk>null</jk>.
578    * @param action The action to perform.  Must not be <jk>null</jk>.
579    */
580   public static <E> void forEachReverse(E[] value, Consumer<E> action) {
581      for (var i = value.length - 1; i >= 0; i--)
582         action.accept(value[i]);
583   }
584
585   /**
586    * Iterates the specified list in reverse order.
587    *
588    * @param <E> The element type.
589    * @param value The list to iterate.  Must not be <jk>null</jk>.
590    * @param action The action to perform.  Must not be <jk>null</jk>.
591    */
592   public static <E> void forEachReverse(List<E> value, Consumer<E> action) {
593      if (value instanceof ArrayList) {
594         for (var i = value.size() - 1; i >= 0; i--)
595            action.accept(value.get(i));
596      } else {
597         ListIterator<E> i = value.listIterator(value.size());
598         while (i.hasPrevious())
599            action.accept(i.previous());
600      }
601   }
602
603   /**
604    * Returns the index position of the element in the specified array using the {@link String#equals(Object)} method.
605    *
606    * @param element The element to check for.
607    * @param array The array to check.
608    * @return
609    *    The index position of the element in the specified array, or
610    *    <c>-1</c> if the array doesn't contain the element, or the array or element is <jk>null</jk>.
611    */
612   public static <T> int indexOf(T element, T[] array) {
613      if (element == null || array == null)
614         return -1;
615      for (var i = 0; i < array.length; i++)
616         if (equal(element, array[i]))
617            return i;
618      return -1;
619   }
620
621   /**
622    * Returns <jk>true</jk> if the specified collection is null or empty.
623    *
624    * @param c The collection to check.
625    * @return <jk>true</jk> if the specified collection is null or empty.
626    */
627   public static boolean isEmpty(Collection<?> c) {
628      return c == null || c.isEmpty();
629   }
630
631   /**
632    * Returns <jk>true</jk> if the specified map is null or empty.
633    *
634    * @param m The map to check.
635    * @return <jk>true</jk> if the specified map is null or empty.
636    */
637   public static boolean isEmpty(Map<?,?> m) {
638      return m == null || m.isEmpty();
639   }
640
641   /**
642    * Returns <jk>true</jk> if the specified array is null or has a length of zero.
643    *
644    * @param array The array to check.
645    * @return <jk>true</jk> if the specified array is null or has a length of zero.
646    */
647   public static boolean isEmptyArray(Object[] array) {
648      return array == null || array.length == 0;
649   }
650
651   /**
652    * Returns <jk>true</jk> if the specified array is not null and has a length greater than zero.
653    *
654    * @param array The array to check.
655    * @return <jk>true</jk> if the specified array is not null and has a length greater than zero.
656    */
657   public static boolean isNotEmptyArray(Object[] array) {
658      return isNotNull(array) && array.length > 0;
659   }
660
661   /**
662    * Creates a fixed-size list backed by the specified array (via {@link Arrays#asList(Object...)}).
663    *
664    * <p>
665    * The returned list is fixed-size: element values can be replaced via {@link List#set(int, Object)},
666    * but elements cannot be added or removed. Returns <jk>null</jk> if the input array is <jk>null</jk>.
667    * This differs from {@link #list(Object...)}, which returns a fully-modifiable {@link ArrayList}.
668    *
669    * @param <T> The element type.
670    * @param values The values to add to the list.
671    * @return A fixed-size list containing the specified values, or <jk>null</jk> if the input is <jk>null</jk>.
672    */
673   @SafeVarargs
674   public static <T> List<T> fixedSizeList(T...values) {
675      return values == null ? null : Arrays.asList(values);
676   }
677
678   /**
679    * Returns the last entry in an array.
680    *
681    * @param <E> The element type.
682    * @param l The array.
683    * @return The last element, or <jk>null</jk> if the array is <jk>null</jk> or empty.
684    */
685   public static <E> E last(E[] l) {
686      return (l == null || l.length == 0) ? null : l[l.length - 1];
687   }
688
689   /**
690    * Returns the last entry in a list.
691    *
692    * @param <E> The element type.
693    * @param l The list.
694    * @return The last element, or <jk>null</jk> if the list is <jk>null</jk> or empty.
695    */
696   public static <E> E last(List<E> l) {
697      return isEmpty(l) ? null : l.get(l.size() - 1);
698   }
699
700   /**
701    * Returns the length of the specified array.
702    *
703    * <p>
704    * This is a null-safe convenience method that wraps {@link Array#getLength(Object)}.
705    * Works with both object arrays and primitive arrays.
706    *
707    * <h5 class='section'>Example:</h5>
708    * <p class='bjava'>
709    *    String[] <jv>array1</jv> = {<js>"foo"</js>, <js>"bar"</js>};
710    *    <jk>int</jk>[] <jv>array2</jv> = {1, 2, 3};
711    *
712    *    <jk>int</jk> <jv>len1</jv> = length(<jv>array1</jv>);  <jc>// Returns 2</jc>
713    *    <jk>int</jk> <jv>len2</jv> = length(<jv>array2</jv>);  <jc>// Returns 3</jc>
714    *    <jk>int</jk> <jv>len3</jv> = length(<jk>null</jk>);    <jc>// Returns 0</jc>
715    * </p>
716    *
717    * @param array The array object. Can be <jk>null</jk>.
718    * @return The length of the array, or <c>0</c> if the array is <jk>null</jk> or not an array.
719    */
720   public static int length(Object array) {
721      if (array == null)
722         return 0;
723      req(array.getClass().isArray(), "Object is not an array");
724      return Array.getLength(array);
725   }
726
727   /**
728    * Shortcut for creating a modifiable list out of an array of values.
729    *
730    * @param <T> The element type.
731    * @param values The values to add to the list.
732    * @return A modifiable list containing the specified values, or <jk>null</jk> if the values array itself is <jk>null</jk>.
733    */
734   @SafeVarargs
735   public static <T> List<T> list(T...values) {
736      return values == null ? null : new ArrayList<>(fixedSizeList(values));
737   }
738
739   /**
740    * Convenience factory for a {@link Lists}.
741    *
742    * @param <E> The element type.
743    * @param type The element type.
744    * @return A new list builder.
745    */
746   public static <E> Lists<E> listBuilder(Class<E> type) {
747      return Lists.create(type);
748   }
749
750   /**
751    * Returns a null list.
752    *
753    * <p>Intentional null return for assertion testing.
754    *
755    * @param <T> The element type.
756    * @param type The element type class.
757    * @return <jk>null</jk>.
758    */
759   public static <T> List<T> nullList(Class<T> type) {
760      return null;
761   }
762
763   /**
764    * Convenience method for creating an {@link ArrayList}.
765    *
766    * @param <E> The element type.
767    * @param elementType The element type.
768    * @param values The values to initialize the list with.  Can be <jk>null</jk> (returns <jk>null</jk>).
769    * @return A new modifiable list, or <jk>null</jk> if the values array itself is <jk>null</jk>.
770    */
771   @SafeVarargs
772   public static <E> List<E> listOfType(Class<E> elementType, E...values) {
773      return list(values);
774   }
775
776   /**
777    * Convenience method for creating an {@link ArrayList} of the specified size.
778    *
779    * @param <E> The element type.
780    * @param size The initial size of the list.
781    * @return A new modifiable list.
782    */
783   public static <E> List<E> listOfSize(int size) {
784      return new ArrayList<>(size);
785   }
786
787   /**
788    * Convenience method for creating an unmodifiable map.
789    *
790    * @param <K> The key type.
791    * @param <V> The value type.
792    * @return A new unmodifiable empty map.
793    */
794   public static <K,V> Map<K,V> immutableMap() {
795      return Map.of();
796   }
797
798   /**
799    * Convenience method for creating an unmodifiable map.
800    * Unlike Map.of(...), supports null keys/values and preserves insertion order.
801    *
802    * @param <K> The key type.
803    * @param <V> The value type.
804    * @param k1 Key 1.
805    * @param v1 Value 1.
806    * @return A new unmodifiable map.
807    */
808   public static <K,V> Map<K,V> immutableMap(K k1, V v1) {
809      return new SimpleMap<>(array(k1), array(v1));
810   }
811
812   /**
813    * Convenience method for creating an unmodifiable map.
814    * Unlike Map.of(...), supports null keys/values and preserves insertion order.
815    *
816    * @param <K> The key type.
817    * @param <V> The value type.
818    * @param k1 Key 1.
819    * @param v1 Value 1.
820    * @param k2 Key 2.
821    * @param v2 Value 2.
822    * @return A new unmodifiable map.
823    */
824   public static <K,V> Map<K,V> immutableMap(K k1, V v1, K k2, V v2) {
825      return new SimpleMap<>(array(k1, k2), array(v1, v2));
826   }
827
828   /**
829    * Convenience method for creating an unmodifiable map.
830    * Unlike Map.of(...), supports null keys/values and preserves insertion order.
831    *
832    * @param <K> The key type.
833    * @param <V> The value type.
834    * @param k1 Key 1.
835    * @param v1 Value 1.
836    * @param k2 Key 2.
837    * @param v2 Value 2.
838    * @param k3 Key 3.
839    * @param v3 Value 3.
840    * @return A new unmodifiable map.
841    */
842   public static <K,V> Map<K,V> immutableMap(K k1, V v1, K k2, V v2, K k3, V v3) {
843      return new SimpleMap<>(array(k1, k2, k3), array(v1, v2, v3));
844   }
845
846   /**
847    * Convenience method for creating an unmodifiable map.
848    * Unlike Map.of(...), supports null keys/values and preserves insertion order.
849    *
850    * @param <K> The key type.
851    * @param <V> The value type.
852    * @param k1 Key 1.
853    * @param v1 Value 1.
854    * @param k2 Key 2.
855    * @param v2 Value 2.
856    * @param k3 Key 3.
857    * @param v3 Value 3.
858    * @param k4 Key 4.
859    * @param v4 Value 4.
860    * @return A new unmodifiable map.
861    */
862   public static <K,V> Map<K,V> immutableMap(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
863      return new SimpleMap<>(array(k1, k2, k3, k4), array(v1, v2, v3, v4));
864   }
865
866   /**
867    * Convenience method for creating an unmodifiable map.
868    * Unlike Map.of(...), supports null keys/values and preserves insertion order.
869    *
870    * @param <K> The key type.
871    * @param <V> The value type.
872    * @param k1 Key 1.
873    * @param v1 Value 1.
874    * @param k2 Key 2.
875    * @param v2 Value 2.
876    * @param k3 Key 3.
877    * @param v3 Value 3.
878    * @param k4 Key 4.
879    * @param v4 Value 4.
880    * @param k5 Key 5.
881    * @param v5 Value 5.
882    * @return A new unmodifiable map.
883    */
884   public static <K,V> Map<K,V> immutableMap(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
885      return new SimpleMap<>(array(k1, k2, k3, k4, k5), array(v1, v2, v3, v4, v5));
886   }
887
888   /**
889    * Convenience method for creating an unmodifiable map.
890    * Unlike Map.of(...), supports null keys/values and preserves insertion order.
891    *
892    * @param <K> The key type.
893    * @param <V> The value type.
894    * @param k1 Key 1.
895    * @param v1 Value 1.
896    * @param k2 Key 2.
897    * @param v2 Value 2.
898    * @param k3 Key 3.
899    * @param v3 Value 3.
900    * @param k4 Key 4.
901    * @param v4 Value 4.
902    * @param k5 Key 5.
903    * @param v5 Value 5.
904    * @param k6 Key 6.
905    * @param v6 Value 6.
906    * @return A new unmodifiable map.
907    */
908   public static <K,V> Map<K,V> immutableMap(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) {
909      return new SimpleMap<>(array(k1, k2, k3, k4, k5, k6), array(v1, v2, v3, v4, v5, v6));
910   }
911
912   /**
913    * Convenience method for creating an unmodifiable map.
914    * Unlike Map.of(...), supports null keys/values and preserves insertion order.
915    *
916    * @param <K> The key type.
917    * @param <V> The value type.
918    * @param k1 Key 1.
919    * @param v1 Value 1.
920    * @param k2 Key 2.
921    * @param v2 Value 2.
922    * @param k3 Key 3.
923    * @param v3 Value 3.
924    * @param k4 Key 4.
925    * @param v4 Value 4.
926    * @param k5 Key 5.
927    * @param v5 Value 5.
928    * @param k6 Key 6.
929    * @param v6 Value 6.
930    * @param k7 Key 7.
931    * @param v7 Value 7.
932    * @return A new unmodifiable map.
933    */
934   public static <K,V> Map<K,V> immutableMap(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) {
935      return new SimpleMap<>(array(k1, k2, k3, k4, k5, k6, k7), array(v1, v2, v3, v4, v5, v6, v7));
936   }
937
938   /**
939    * Convenience method for creating an unmodifiable map.
940    * Unlike Map.of(...), supports null keys/values and preserves insertion order.
941    *
942    * @param <K> The key type.
943    * @param <V> The value type.
944    * @param k1 Key 1.
945    * @param v1 Value 1.
946    * @param k2 Key 2.
947    * @param v2 Value 2.
948    * @param k3 Key 3.
949    * @param v3 Value 3.
950    * @param k4 Key 4.
951    * @param v4 Value 4.
952    * @param k5 Key 5.
953    * @param v5 Value 5.
954    * @param k6 Key 6.
955    * @param v6 Value 6.
956    * @param k7 Key 7.
957    * @param v7 Value 7.
958    * @param k8 Key 8.
959    * @param v8 Value 8.
960    * @return A new unmodifiable map.
961    */
962   public static <K,V> Map<K,V> immutableMap(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) {
963      return new SimpleMap<>(array(k1, k2, k3, k4, k5, k6, k7, k8), array(v1, v2, v3, v4, v5, v6, v7, v8));
964   }
965
966   /**
967    * Convenience method for creating an unmodifiable map.
968    * Unlike Map.of(...), supports null keys/values and preserves insertion order.
969    *
970    * @param <K> The key type.
971    * @param <V> The value type.
972    * @param k1 Key 1.
973    * @param v1 Value 1.
974    * @param k2 Key 2.
975    * @param v2 Value 2.
976    * @param k3 Key 3.
977    * @param v3 Value 3.
978    * @param k4 Key 4.
979    * @param v4 Value 4.
980    * @param k5 Key 5.
981    * @param v5 Value 5.
982    * @param k6 Key 6.
983    * @param v6 Value 6.
984    * @param k7 Key 7.
985    * @param v7 Value 7.
986    * @param k8 Key 8.
987    * @param v8 Value 8.
988    * @param k9 Key 9.
989    * @param v9 Value 9.
990    * @return A new unmodifiable map.
991    */
992   public static <K,V> Map<K,V> immutableMap(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
993      return new SimpleMap<>(array(k1, k2, k3, k4, k5, k6, k7, k8, k9), array(v1, v2, v3, v4, v5, v6, v7, v8, v9));
994   }
995
996   /**
997    * Convenience method for creating an unmodifiable map.
998    * Unlike Map.of(...), supports null keys/values and preserves insertion order.
999    *
1000    * @param <K> The key type.
1001    * @param <V> The value type.
1002    * @param k1 Key 1.
1003    * @param v1 Value 1.
1004    * @param k2 Key 2.
1005    * @param v2 Value 2.
1006    * @param k3 Key 3.
1007    * @param v3 Value 3.
1008    * @param k4 Key 4.
1009    * @param v4 Value 4.
1010    * @param k5 Key 5.
1011    * @param v5 Value 5.
1012    * @param k6 Key 6.
1013    * @param v6 Value 6.
1014    * @param k7 Key 7.
1015    * @param v7 Value 7.
1016    * @param k8 Key 8.
1017    * @param v8 Value 8.
1018    * @param k9 Key 9.
1019    * @param v9 Value 9.
1020    * @param k10 Key 10.
1021    * @param v10 Value 10.
1022    * @return A new unmodifiable map.
1023    */
1024   public static <K,V> Map<K,V> immutableMap(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
1025      return new SimpleMap<>(array(k1, k2, k3, k4, k5, k6, k7, k8, k9, k10), array(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10));
1026   }
1027
1028   /**
1029    * Convenience method for creating an unmodifiable set.
1030    * Unlike Set.of(...), supports a null element and preserves insertion order.
1031    *
1032    * @param <E> The element type.
1033    * @param values The values to initialize the set with.  Must not be <jk>null</jk> (a <jk>null</jk> array throws {@link IllegalArgumentException}).
1034    * @return A new unmodifiable set.
1035    */
1036   @SafeVarargs
1037   public static <E> Set<E> immutableSet(E...values) {
1038      reqnn("values", values);
1039      return Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(values)));
1040   }
1041
1042   /**
1043    * Convenience method for creating a {@link LinkedHashMap}.
1044    *
1045    * @param <K> The key type.
1046    * @param <V> The value type.
1047    * @return A new modifiable map.
1048    */
1049   public static <K,V> Map<K,V> map() {
1050      return new LinkedHashMap<>();
1051   }
1052
1053   //-----------------------------------------------------------------------------------------------------------------
1054   // Array utilities
1055   //-----------------------------------------------------------------------------------------------------------------
1056
1057   /**
1058    * Convenience method for creating a {@link LinkedHashMap}.
1059    *
1060    * @param <K> The key type.
1061    * @param <V> The value type.
1062    * @param k1 Key 1.
1063    * @param v1 Value 1.
1064    * @return A new modifiable map.
1065    */
1066   public static <K,V> Map<K,V> map(K k1, V v1) {
1067      var m = new LinkedHashMap<K,V>();
1068      m.put(k1, v1);
1069      return m;
1070   }
1071
1072   /**
1073    * Convenience method for creating a {@link LinkedHashMap}.
1074    *
1075    * @param <K> The key type.
1076    * @param <V> The value type.
1077    * @param k1 Key 1.
1078    * @param v1 Value 1.
1079    * @param k2 Key 2.
1080    * @param v2 Value 2.
1081    * @return A new modifiable map.
1082    */
1083   public static <K,V> Map<K,V> map(K k1, V v1, K k2, V v2) {
1084      var m = new LinkedHashMap<K,V>();
1085      m.put(k1, v1);
1086      m.put(k2, v2);
1087      return m;
1088   }
1089
1090   /**
1091    * Convenience method for creating a {@link LinkedHashMap}.
1092    *
1093    * @param <K> The key type.
1094    * @param <V> The value type.
1095    * @param k1 Key 1.
1096    * @param v1 Value 1.
1097    * @param k2 Key 2.
1098    * @param v2 Value 2.
1099    * @param k3 Key 3.
1100    * @param v3 Value 3.
1101    * @return A new modifiable map.
1102    */
1103   public static <K,V> Map<K,V> map(K k1, V v1, K k2, V v2, K k3, V v3) {
1104      var m = new LinkedHashMap<K,V>();
1105      m.put(k1, v1);
1106      m.put(k2, v2);
1107      m.put(k3, v3);
1108      return m;
1109   }
1110
1111   /**
1112    * Convenience method for creating a {@link LinkedHashMap}.
1113    *
1114    * @param <K> The key type.
1115    * @param <V> The value type.
1116    * @param k1 Key 1.
1117    * @param v1 Value 1.
1118    * @param k2 Key 2.
1119    * @param v2 Value 2.
1120    * @param k3 Key 3.
1121    * @param v3 Value 3.
1122    * @param k4 Key 4.
1123    * @param v4 Value 4.
1124    * @return A new modifiable map.
1125    */
1126   public static <K,V> Map<K,V> map(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
1127      var m = new LinkedHashMap<K,V>();
1128      m.put(k1, v1);
1129      m.put(k2, v2);
1130      m.put(k3, v3);
1131      m.put(k4, v4);
1132      return m;
1133   }
1134
1135   /**
1136    * Convenience method for creating a {@link LinkedHashMap}.
1137    *
1138    * @param <K> The key type.
1139    * @param <V> The value type.
1140    * @param k1 Key 1.
1141    * @param v1 Value 1.
1142    * @param k2 Key 2.
1143    * @param v2 Value 2.
1144    * @param k3 Key 3.
1145    * @param v3 Value 3.
1146    * @param k4 Key 4.
1147    * @param v4 Value 4.
1148    * @param k5 Key 5.
1149    * @param v5 Value 5.
1150    * @return A new modifiable map.
1151    */
1152   public static <K,V> Map<K,V> map(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
1153      var m = new LinkedHashMap<K,V>();
1154      m.put(k1, v1);
1155      m.put(k2, v2);
1156      m.put(k3, v3);
1157      m.put(k4, v4);
1158      m.put(k5, v5);
1159      return m;
1160   }
1161
1162   /**
1163    * Convenience method for creating a {@link LinkedHashMap}.
1164    *
1165    * @param <K> The key type.
1166    * @param <V> The value type.
1167    * @param k1 Key 1.
1168    * @param v1 Value 1.
1169    * @param k2 Key 2.
1170    * @param v2 Value 2.
1171    * @param k3 Key 3.
1172    * @param v3 Value 3.
1173    * @param k4 Key 4.
1174    * @param v4 Value 4.
1175    * @param k5 Key 5.
1176    * @param v5 Value 5.
1177    * @param k6 Key 6.
1178    * @param v6 Value 6.
1179    * @return A new modifiable map.
1180    */
1181   public static <K,V> Map<K,V> map(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) {
1182      var m = new LinkedHashMap<K,V>();
1183      m.put(k1, v1);
1184      m.put(k2, v2);
1185      m.put(k3, v3);
1186      m.put(k4, v4);
1187      m.put(k5, v5);
1188      m.put(k6, v6);
1189      return m;
1190   }
1191
1192   /**
1193    * Convenience method for creating a {@link LinkedHashMap}.
1194    *
1195    * @param <K> The key type.
1196    * @param <V> The value type.
1197    * @param k1 Key 1.
1198    * @param v1 Value 1.
1199    * @param k2 Key 2.
1200    * @param v2 Value 2.
1201    * @param k3 Key 3.
1202    * @param v3 Value 3.
1203    * @param k4 Key 4.
1204    * @param v4 Value 4.
1205    * @param k5 Key 5.
1206    * @param v5 Value 5.
1207    * @param k6 Key 6.
1208    * @param v6 Value 6.
1209    * @param k7 Key 7.
1210    * @param v7 Value 7.
1211    * @return A new modifiable map.
1212    */
1213   public static <K,V> Map<K,V> map(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) {
1214      var m = new LinkedHashMap<K,V>();
1215      m.put(k1, v1);
1216      m.put(k2, v2);
1217      m.put(k3, v3);
1218      m.put(k4, v4);
1219      m.put(k5, v5);
1220      m.put(k6, v6);
1221      m.put(k7, v7);
1222      return m;
1223   }
1224
1225   /**
1226    * Convenience method for creating a {@link LinkedHashMap}.
1227    *
1228    * @param <K> The key type.
1229    * @param <V> The value type.
1230    * @param k1 Key 1.
1231    * @param v1 Value 1.
1232    * @param k2 Key 2.
1233    * @param v2 Value 2.
1234    * @param k3 Key 3.
1235    * @param v3 Value 3.
1236    * @param k4 Key 4.
1237    * @param v4 Value 4.
1238    * @param k5 Key 5.
1239    * @param v5 Value 5.
1240    * @param k6 Key 6.
1241    * @param v6 Value 6.
1242    * @param k7 Key 7.
1243    * @param v7 Value 7.
1244    * @param k8 Key 8.
1245    * @param v8 Value 8.
1246    * @return A new modifiable map.
1247    */
1248   public static <K,V> Map<K,V> map(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) {
1249      var m = new LinkedHashMap<K,V>();
1250      m.put(k1, v1);
1251      m.put(k2, v2);
1252      m.put(k3, v3);
1253      m.put(k4, v4);
1254      m.put(k5, v5);
1255      m.put(k6, v6);
1256      m.put(k7, v7);
1257      m.put(k8, v8);
1258      return m;
1259   }
1260
1261   /**
1262    * Convenience method for creating a {@link LinkedHashMap}.
1263    *
1264    * @param <K> The key type.
1265    * @param <V> The value type.
1266    * @param k1 Key 1.
1267    * @param v1 Value 1.
1268    * @param k2 Key 2.
1269    * @param v2 Value 2.
1270    * @param k3 Key 3.
1271    * @param v3 Value 3.
1272    * @param k4 Key 4.
1273    * @param v4 Value 4.
1274    * @param k5 Key 5.
1275    * @param v5 Value 5.
1276    * @param k6 Key 6.
1277    * @param v6 Value 6.
1278    * @param k7 Key 7.
1279    * @param v7 Value 7.
1280    * @param k8 Key 8.
1281    * @param v8 Value 8.
1282    * @param k9 Key 9.
1283    * @param v9 Value 9.
1284    * @return A new modifiable map.
1285    */
1286   public static <K,V> Map<K,V> map(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
1287      var m = new LinkedHashMap<K,V>();
1288      m.put(k1, v1);
1289      m.put(k2, v2);
1290      m.put(k3, v3);
1291      m.put(k4, v4);
1292      m.put(k5, v5);
1293      m.put(k6, v6);
1294      m.put(k7, v7);
1295      m.put(k8, v8);
1296      m.put(k9, v9);
1297      return m;
1298   }
1299
1300   /**
1301    * Convenience method for creating a {@link LinkedHashMap}.
1302    *
1303    * @param <K> The key type.
1304    * @param <V> The value type.
1305    * @param k1 Key 1.
1306    * @param v1 Value 1.
1307    * @param k2 Key 2.
1308    * @param v2 Value 2.
1309    * @param k3 Key 3.
1310    * @param v3 Value 3.
1311    * @param k4 Key 4.
1312    * @param v4 Value 4.
1313    * @param k5 Key 5.
1314    * @param v5 Value 5.
1315    * @param k6 Key 6.
1316    * @param v6 Value 6.
1317    * @param k7 Key 7.
1318    * @param v7 Value 7.
1319    * @param k8 Key 8.
1320    * @param v8 Value 8.
1321    * @param k9 Key 9.
1322    * @param v9 Value 9.
1323    * @param k10 Key 10.
1324    * @param v10 Value 10.
1325    * @return A new modifiable map.
1326    */
1327   public static <K,V> Map<K,V> map(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
1328      var m = new LinkedHashMap<K,V>();
1329      m.put(k1, v1);
1330      m.put(k2, v2);
1331      m.put(k3, v3);
1332      m.put(k4, v4);
1333      m.put(k5, v5);
1334      m.put(k6, v6);
1335      m.put(k7, v7);
1336      m.put(k8, v8);
1337      m.put(k9, v9);
1338      m.put(k10, v10);
1339      return m;
1340   }
1341
1342   /**
1343    * Convenience factory for a {@link Maps} builder.
1344    *
1345    * <p>
1346    * This is a shortcut for <c>Maps.create().ordered()</c>.
1347    *
1348    * <h5 class='section'>Example:</h5>
1349    * <p class='bjava'>
1350    *    Map&lt;String,Object&gt; <jv>map</jv> = mapBuilder()
1351    *       .add(<js>"foo"</js>, 1)
1352    *       .add(<js>"bar"</js>, 2)
1353    *       .build();
1354    * </p>
1355    *
1356    * @param <K> The key type.
1357    * @param <V> The value type.
1358    * @return A new map builder.
1359    * @see Maps
1360    */
1361   public static <K,V> Maps<K,V> mapBuilder() {
1362      return (Maps<K,V>)Maps.create().ordered();
1363   }
1364
1365   /**
1366    * Convenience factory for a {@link Maps} with {@link String} keys and {@link Object} values.
1367    *
1368    * <p>
1369    * This is a shortcut for <c>Maps.create(String.<jk>class</jk>, Object.<jk>class</jk>)</c>.
1370    *
1371    * <h5 class='section'>Example:</h5>
1372    * <p class='bjava'>
1373    *    Map&lt;String,Object&gt; <jv>map</jv> = mapBuilder()
1374    *       .add(<js>"foo"</js>, 1)
1375    *       .add(<js>"bar"</js>, 2)
1376    *       .build();
1377    * </p>
1378    *
1379    * <p>
1380    * This builder supports optional filtering to automatically exclude unwanted values:
1381    * <p class='bjava'>
1382    *    <jc>// Build a map excluding null and empty values</jc>
1383    *    Map&lt;String,Object&gt; <jv>map</jv> = mapBuilder().filtered()
1384    *       .add(<js>"foo"</js>, <jk>null</jk>)       <jc>// Excluded</jc>
1385    *       .add(<js>"bar"</js>, <js>""</js>)         <jc>// Excluded</jc>
1386    *       .add(<js>"baz"</js>, <js>"value"</js>)    <jc>// Included</jc>
1387    *       .build();
1388    * </p>
1389    *
1390    * @return A new map builder.
1391    * @see Maps
1392    */
1393   @SuppressWarnings({
1394      "java:S100" // Method name uses underscore convention
1395   })
1396   public static Maps<String,Object> mapb_so() {
1397      return Maps.create(String.class, Object.class).ordered();
1398   }
1399
1400   /**
1401    * Convenience factory for a filtered, sorted, fluent map with {@link String} keys and {@link Object} values.
1402    *
1403    * <p>
1404    * This is a shortcut for <c>Maps.create(String.<jk>class</jk>, Object.<jk>class</jk>).filtered().sorted().buildFluent()</c>.
1405    *
1406    * <p>
1407    * This is typically used for creating property maps in <c>toString()</c> methods that need to be sorted and filtered.
1408    *
1409    * <h5 class='section'>Example:</h5>
1410    * <p class='bjava'>
1411    *    <jc>// In a properties() method</jc>
1412    *    <jk>return</jk> filteredBeanPropertyMap()
1413    *       .a(<js>"name"</js>, <jv>name</jv>)
1414    *       .a(<js>"value"</js>, <jv>value</jv>);
1415    * </p>
1416    *
1417    * @return A new filtered, sorted, fluent map builder.
1418    * @see FluentMap
1419    * @see Maps
1420    */
1421   public static FluentMap<String,Object> filteredBeanPropertyMap() {
1422      return Maps.create(String.class, Object.class).filtered().sorted().buildFluent();
1423   }
1424
1425   /**
1426    * Convenience factory for a {@link Maps}.
1427    *
1428    * @param <K> The key type.
1429    * @param <V> The value type.
1430    * @param keyType The key type.
1431    * @param valueType The value type.
1432    * @return A new map builder.
1433    */
1434   public static <K,V> Maps<K,V> mapBuilder(Class<K> keyType, Class<V> valueType) {
1435      return Maps.create(keyType, valueType).ordered();
1436   }
1437
1438   /**
1439    * Returns a null map.
1440    *
1441    * <p>Intentional null return for assertion testing.
1442    *
1443    * @param <K> The key type.
1444    * @param <V> The value type.
1445    * @param keyType The key type class.
1446    * @param valueType The value type class.
1447    * @return <jk>null</jk>.
1448    */
1449   public static <K,V> Map<K,V> nullMap(Class<K> keyType, Class<V> valueType) {
1450      return null;
1451   }
1452
1453   /**
1454    * Convenience method for creating a {@link LinkedHashMap}.
1455    *
1456    * @param <K> The key type.
1457    * @param <V> The value type.
1458    * @param keyType The key type.
1459    * @param valueType The value type.
1460    * @return A new modifiable map.
1461    */
1462   public static <K,V> Map<K,V> mapOfType(Class<K> keyType, Class<V> valueType) {
1463      return map();
1464   }
1465
1466   /**
1467    * Adds all the specified values to the specified collection.
1468    * Creates a new set if the value is <jk>null</jk>.
1469    *
1470    * @param <E> The element type.
1471    * @param value The collection to add to.  Can be <jk>null</jk> (a new list is created and returned).
1472    * @param entries The entries to add.  Can be <jk>null</jk> (treated as a no-op — the value is returned unchanged).
1473    * @return The set.
1474    */
1475   @SafeVarargs
1476   public static <E> List<E> prependAll(List<E> value, E...entries) {
1477      if (isNotNull(entries)) {
1478         if (value == null)
1479            value = list(entries);
1480         else
1481            value.addAll(0, fixedSizeList(entries));
1482      }
1483      return value;
1484   }
1485
1486   /**
1487    * Reverses the elements in the specified array in-place.
1488    *
1489    * @param <E> The element type.
1490    * @param array The array to reverse.  Must not be <jk>null</jk>.
1491    * @return The same array, reversed.
1492    */
1493   public static <E> E[] reverse(E[] array) {
1494      for (var i = 0; i < array.length / 2; i++) {
1495         E temp = array[i];
1496         array[i] = array[array.length - i - 1];
1497         array[array.length - i - 1] = temp;
1498      }
1499      return array;
1500   }
1501
1502   /**
1503    * Returns a reversed view of the specified list.
1504    *
1505    * <p>
1506    * The returned list is a live view that reflects changes to the original list.
1507    *
1508    * @param <E> The element type.
1509    * @param list The list to reverse.  Must not be <jk>null</jk> (a <jk>null</jk> argument throws {@link IllegalArgumentException}).
1510    * @return A reversed view of the list.
1511    */
1512   public static <E> List<E> reverse(List<E> list) {
1513      return new ReversedList<>(list);
1514   }
1515
1516   /**
1517    * Returns a reverse stream of the specified list.
1518    *
1519    * <h5 class='section'>Example:</h5>
1520    * <p class='bjava'>
1521    *    List&lt;String&gt; <jv>list</jv> = <jsm>list</jsm>(<js>"a"</js>, <js>"b"</js>, <js>"c"</js>);
1522    *    Stream&lt;String&gt; <jv>reversed</jv> = <jsm>rstream</jsm>(<jv>list</jv>);
1523    *    <jc>// Produces stream: "c", "b", "a"</jc>
1524    * </p>
1525    *
1526    * @param <T> The element type.
1527    * @param value The list to stream in reverse order. Can be <jk>null</jk>.
1528    * @return A stream of the list elements in reverse order, or an empty stream if the list is <jk>null</jk> or empty.
1529    */
1530   public static <T> Stream<T> rstream(List<T> value) {
1531      if (value == null || value.isEmpty())
1532         return Stream.empty();
1533      return IntStream.range(0, value.size()).mapToObj(i -> value.get(value.size() - 1 - i));
1534   }
1535
1536   /**
1537    * Removes negation tokens from a list.
1538    *
1539    * <p>
1540    * A negation token is a string starting with <js>'-'</js> followed by at least one character.
1541    * When encountered, it removes the first prior occurrence of the corresponding positive token.
1542    *
1543    * <h5 class='section'>Example:</h5>
1544    * <p class='bjava'>
1545    *    List&lt;String&gt; <jv>result</jv> = <jsm>removeNegations</jsm>(list(<js>"a"</js>, <js>"b"</js>, <js>"-a"</js>, <js>"c"</js>));
1546    *    <jc>// Produces: ["b", "c"]</jc>
1547    * </p>
1548    *
1549    * @param input The input list. Cannot be <jk>null</jk>.
1550    * @return The list with negation tokens applied, or the original list if no negation tokens were present.
1551    */
1552   public static List<String> removeNegations(List<String> input) {
1553      reqnn("input", input);
1554      var hasNegation = false;
1555      for (var token : input) {
1556         if (token != null && token.length() > 1 && token.charAt(0) == '-') {
1557            hasNegation = true;
1558            break;
1559         }
1560      }
1561      if (!hasNegation)
1562         return input;
1563      var out = new ArrayList<String>(input.size());
1564      for (var token : input) {
1565         if (token != null && token.length() > 1 && token.charAt(0) == '-')
1566            out.remove(token.substring(1));
1567         else
1568            out.add(token);
1569      }
1570      return out;
1571   }
1572
1573   /**
1574    * Creates a {@link TreeSet} with a custom comparator from a collection of elements.
1575    *
1576    * <p>
1577    * Null elements in the collection are silently skipped.
1578    *
1579    * @param <E> The element type.
1580    * @param comparator The comparator to use for ordering. Cannot be <jk>null</jk>.
1581    * @param elements The initial elements. Can be <jk>null</jk> (treated as empty).
1582    * @return A new {@link TreeSet} containing all non-null elements from the collection.
1583    */
1584   public static <E> SortedSet<E> treeSet(Comparator<? super E> comparator, Collection<? extends E> elements) {
1585      reqnn("comparator", comparator);
1586      if (elements == null)
1587         return new TreeSet<E>(comparator);
1588      return elements.stream().filter(Objects::nonNull).collect(Collectors.toCollection(() -> new TreeSet<E>(comparator)));
1589   }
1590
1591   /**
1592    * Creates a case-insensitive {@link TreeSet} from a collection of strings.
1593    *
1594    * <p>
1595    * Equivalent to <c>treeSet(String.CASE_INSENSITIVE_ORDER, elements)</c>.
1596    * Null elements in the collection are silently skipped.
1597    *
1598    * @param elements The initial elements. Can be <jk>null</jk> (treated as empty).
1599    * @return A new case-insensitive {@link TreeSet} containing all non-null elements from the collection.
1600    */
1601   public static SortedSet<String> treeSetCi(Collection<String> elements) {
1602      return treeSet(String.CASE_INSENSITIVE_ORDER, elements);
1603   }
1604
1605   /**
1606    * Convenience factory for a {@link Sets}.
1607    *
1608    * @param <E> The element type.
1609    * @param type The element type.
1610    * @return A new set builder.
1611    */
1612   public static <E> Sets<E> setBuilder(Class<E> type) {
1613      return Sets.create(type).ordered();
1614   }
1615
1616   /**
1617    * Convenience method for creating a {@link LinkedHashSet}.
1618    *
1619    * @param <E> The element type.
1620    * @param elementType The element type.
1621    * @param values The values to initialize the set with.  Must not be <jk>null</jk> (a <jk>null</jk> array throws {@link IllegalArgumentException}).
1622    * @return A new modifiable set.
1623    */
1624   @SafeVarargs
1625   public static <E> Set<E> setOfType(Class<E> elementType, E...values) {
1626      return set(values);
1627   }
1628
1629   /**
1630    * Convenience method for creating an {@link ArrayList} and sorting it.
1631    *
1632    * @param <E> The element type.
1633    * @param comparator The comparator to use to sort the list.  Can be <jk>null</jk> (natural ordering is used).
1634    * @param value The values to initialize the list with.  Can be <jk>null</jk> (returns an empty list).
1635    * @return A new modifiable list.
1636    */
1637   public static <E> List<E> sortedList(Comparator<E> comparator, Collection<E> value) {
1638      List<E> l = toList(value);
1639      l.sort(comparator);
1640      return l;
1641   }
1642
1643   /**
1644    * Convenience method for creating an {@link ArrayList} and sorting it.
1645    *
1646    * @param <E> The element type.
1647    * @param comparator The comparator to use to sort the list.  Can be <jk>null</jk> (natural ordering is used).
1648    * @param values The values to initialize the list with.  Must not be <jk>null</jk>.
1649    * @return A new modifiable list.
1650    */
1651   public static <E> List<E> sortedList(Comparator<E> comparator, E[] values) {
1652      List<E> l = list(values);
1653      l.sort(comparator);
1654      return l;
1655   }
1656
1657   /**
1658    * Convenience method for creating an {@link ArrayList} and sorting it.
1659    *
1660    * @param <E> The element type.
1661    * @param values The values to initialize the list with.  Must not be <jk>null</jk>.
1662    * @return A new modifiable list.
1663    */
1664   @SafeVarargs
1665   public static <E> List<E> sortedList(E...values) {
1666      List<E> l = list(values);
1667      ((List<Comparable>)l).sort(null);
1668      return l;
1669   }
1670
1671   /**
1672    * Convenience method for creating a {@link TreeMap}.
1673    *
1674    * @param <K> The key type.
1675    * @param <V> The value type.
1676    * @return A new modifiable set.
1677    */
1678   public static <K,V> SortedMap<K,V> sortedMap() {
1679      return new TreeMap<>();
1680   }
1681
1682   /**
1683    * Convenience method for creating a {@link TreeSet}.
1684    *
1685    * <p>
1686    * Note: <jk>null</jk> values in the varargs array are automatically filtered out
1687    * because {@link TreeSet} does not support <jk>null</jk> elements.
1688    *
1689    * @param <E> The element type.
1690    * @param values The values to initialize the set with.
1691    *    <br>Must not be <jk>null</jk> (a <jk>null</jk> array throws {@link IllegalArgumentException}).
1692    *    <br>Can contain <jk>null</jk> values (they will be filtered out).
1693    * @return A new modifiable set.
1694    */
1695   @SafeVarargs
1696   public static <E> SortedSet<E> sortedSet(E...values) {
1697      reqnn("values", values);
1698      return Arrays.stream(values).filter(Objects::nonNull).collect(Collectors.toCollection(TreeSet::new));
1699   }
1700
1701   /**
1702    * Returns a stream of the specified array.
1703    *
1704    * <p>
1705    * Gracefully handles <jk>null</jk> arrays by returning an empty stream.
1706    *
1707    * <h5 class='section'>Example:</h5>
1708    * <p class='bjava'>
1709    *    String[] <jv>array</jv> = {<js>"a"</js>, <js>"b"</js>, <js>"c"</js>};
1710    *
1711    *    <jc>// Prints "a", "b", "c"</jc>
1712    *    <jsm>stream</jsm>(<jv>array</jv>).forEach(System.<jk>out</jk>::println);
1713    *
1714    *    <jc>// Handles null gracefully - returns empty stream</jc>
1715    *    <jsm>stream</jsm>(<jk>null</jk>).forEach(System.<jk>out</jk>::println);  <jc>// Prints nothing</jc>
1716    * </p>
1717    *
1718    * @param <T> The element type.
1719    * @param array The array to stream. Can be <jk>null</jk>.
1720    * @return A stream of the array elements, or an empty stream if the array is <jk>null</jk>.
1721    */
1722   public static <T> Stream<T> stream(T[] array) {
1723      return array == null ? Stream.empty() : Arrays.stream(array);
1724   }
1725
1726   /**
1727    * Wraps the specified list in a synchronized (thread-safe) view via {@link Collections#synchronizedList(List)}.
1728    *
1729    * @param <E> The element type.
1730    * @param value The list to wrap.  Can be <jk>null</jk> (returns <jk>null</jk>).
1731    * @return A synchronized view of the list, or <jk>null</jk> if the input was <jk>null</jk>.
1732    */
1733   public static <E> List<E> synced(List<E> value) {
1734      return value == null ? null : Collections.synchronizedList(value);
1735   }
1736
1737   /**
1738    * Wraps the specified map in a synchronized (thread-safe) view via {@link Collections#synchronizedMap(Map)}.
1739    *
1740    * @param <K> The key type.
1741    * @param <V> The value type.
1742    * @param value The map to wrap.  Can be <jk>null</jk> (returns <jk>null</jk>).
1743    * @return A synchronized view of the map, or <jk>null</jk> if the input was <jk>null</jk>.
1744    */
1745   public static <K,V> Map<K,V> synced(Map<K,V> value) {
1746      return value == null ? null : Collections.synchronizedMap(value);
1747   }
1748
1749   /**
1750    * Wraps the specified set in a synchronized (thread-safe) view via {@link Collections#synchronizedSet(Set)}.
1751    *
1752    * @param <E> The element type.
1753    * @param value The set to wrap.  Can be <jk>null</jk> (returns <jk>null</jk>).
1754    * @return A synchronized view of the set, or <jk>null</jk> if the input was <jk>null</jk>.
1755    */
1756   public static <E> Set<E> synced(Set<E> value) {
1757      return value == null ? null : Collections.synchronizedSet(value);
1758   }
1759
1760   /**
1761    * Converts the specified collection to an array.
1762    *
1763    * <p>
1764    * Works on both object and primitive arrays.
1765    *
1766    * @param <E> The element type.
1767    * @param c The collection to convert to an array.  Must not be <jk>null</jk>.
1768    * @param elementType The component type of the collection.  Must not be <jk>null</jk>.
1769    * @return A new array.
1770    */
1771   public static <E> Object toArray(Collection<?> c, Class<E> elementType) {
1772      var a = Array.newInstance(elementType, c.size());
1773      Iterator<?> it = c.iterator();
1774      int i = 0;
1775      while (it.hasNext())
1776         Array.set(a, i++, it.next());
1777      return a;
1778   }
1779
1780   /**
1781    * Creates an {@link ArrayList} copy from a collection.
1782    *
1783    * @param <E> The element type.
1784    * @param value The collection to copy from.  Can be <jk>null</jk> (returns an empty list).
1785    * @return A new modifiable list.
1786    */
1787   public static <E> List<E> toList(Collection<E> value) {
1788      return toList(value, false);
1789   }
1790
1791   /**
1792    * Creates an {@link ArrayList} copy from a collection.
1793    *
1794    * @param <E> The element type.
1795    * @param value The collection to copy from.  Can be <jk>null</jk>.
1796    * @param nullIfEmpty If <jk>true</jk> will return <jk>null</jk> if the collection is empty or null.
1797    * @return A new modifiable list, or an empty list if the input was <jk>null</jk> (when nullIfEmpty is false), or <jk>null</jk> if nullIfEmpty and the input was null or empty.
1798    */
1799   public static <E> List<E> toList(Collection<E> value, boolean nullIfEmpty) {
1800      if (value == null)
1801         return nullIfEmpty ? null : new ArrayList<>();
1802      if (nullIfEmpty && value.isEmpty())
1803         return null;
1804      var l = new ArrayList<E>();
1805      value.forEach(l::add);
1806      return l;
1807   }
1808
1809   /**
1810    * Converts various collection-like objects to a {@link List}.
1811    *
1812    * <p>This utility method enables testing of any collection-like object by converting it to a List that can be
1813    * passed to methods such as TestUtils.assertList().</p>
1814    *
1815    * <h5 class='section'>Supported Input Types:</h5>
1816    * <ul>
1817    *    <li><b>List:</b> Returns the input unchanged</li>
1818    *    <li><b>Iterable:</b> Any collection, set, queue, etc. (converted to List preserving order)</li>
1819    *    <li><b>Iterator:</b> Converts iterator contents to List</li>
1820    *    <li><b>Enumeration:</b> Converts enumeration contents to List</li>
1821    *    <li><b>Stream:</b> Converts stream contents to List (stream is consumed)</li>
1822    *    <li><b>Map:</b> Converts map entries to List of Map.Entry objects</li>
1823    *    <li><b>Array:</b> Converts any array type (including primitive arrays) to List</li>
1824    * </ul>
1825    *
1826    * <h5 class='section'>Usage Examples:</h5>
1827    * <p class='bjava'>
1828    *    <jc>// Test a Set</jc>
1829    *    Set&lt;String&gt; <jv>mySet</jv> = Set.of(<js>"a"</js>, <js>"b"</js>, <js>"c"</js>);
1830    *    assertList(toList(<jv>mySet</jv>), <js>"a"</js>, <js>"b"</js>, <js>"c"</js>);
1831    *
1832    *    <jc>// Test an array</jc>
1833    *    String[] <jv>myArray</jv> = {<js>"x"</js>, <js>"y"</js>, <js>"z"</js>};
1834    *    assertList(toList(<jv>myArray</jv>), <js>"x"</js>, <js>"y"</js>, <js>"z"</js>);
1835    *
1836    *    <jc>// Test a primitive array</jc>
1837    *    <jk>int</jk>[] <jv>numbers</jv> = {1, 2, 3};
1838    *    assertList(toList(<jv>numbers</jv>), <js>"1"</js>, <js>"2"</js>, <js>"3"</js>);
1839    *
1840    *    <jc>// Test a Stream</jc>
1841    *    Stream&lt;String&gt; <jv>myStream</jv> = Stream.of(<js>"foo"</js>, <js>"bar"</js>);
1842    *    assertList(toList(<jv>myStream</jv>), <js>"foo"</js>, <js>"bar"</js>);
1843    *
1844    *    <jc>// Test a Map (converted to entries)</jc>
1845    *    Map&lt;String,Integer&gt; <jv>myMap</jv> = Map.of(<js>"a"</js>, 1, <js>"b"</js>, 2);
1846    *    assertList(toList(<jv>myMap</jv>), <js>"a=1"</js>, <js>"b=2"</js>);
1847    *
1848    *    <jc>// Test any Iterable collection</jc>
1849    *    Queue&lt;String&gt; <jv>myQueue</jv> = new LinkedList&lt;&gt;(List.of(<js>"first"</js>, <js>"second"</js>));
1850    *    assertList(toList(<jv>myQueue</jv>), <js>"first"</js>, <js>"second"</js>);
1851    * </p>
1852    *
1853    * <h5 class='section'>Integration with Testing:</h5>
1854    * <p>This method is specifically designed to work with testing frameworks to provide
1855    * a unified testing approach for all collection-like types. Instead of having separate assertion methods
1856    * for arrays, sets, and other collections, you can convert them all to Lists and use standard
1857    * list assertion methods.</p>
1858    *
1859    * @param o The object to convert to a List. Must not be null and must be a supported collection-like type.
1860    * @return A {@link List} containing the elements from the input object.
1861    * @throws IllegalArgumentException if the input object cannot be converted to a List.
1862    * @see #arrayToList(Object)
1863    */
1864   @SuppressWarnings({
1865      "java:S1452"  // Wildcard required - List<?> for heterogeneous collections from various sources
1866   })
1867   public static final List<?> toList(Object o) {
1868      reqnn("o", o);
1869      if (o instanceof List<?> o2)
1870         return o2;
1871      if (o instanceof Iterable<?> o2)
1872         return StreamSupport.stream(o2.spliterator(), false).toList();
1873      if (o instanceof Iterator<?> o2)
1874         return StreamSupport.stream(Spliterators.spliteratorUnknownSize(o2, 0), false).toList();
1875      if (o instanceof Enumeration<?> o2)
1876         return Collections.list(o2);
1877      if (o instanceof Stream<?> o2)
1878         return o2.toList();
1879      if (o instanceof Map<?,?> o2)
1880         return toList(o2.entrySet());
1881      if (o instanceof Optional<?> o2)
1882         return o2.isEmpty() ? Collections.emptyList() : Collections.singletonList(o2.get());
1883      if (ClassUtils.isArray(o))
1884         return arrayToList(o);
1885      throw rex("Could not convert object of type %s to a list", ClassUtils.className(o));
1886   }
1887
1888   /**
1889    * Converts the specified array to an <c>ArrayList</c>
1890    *
1891    * @param <E> The element type.
1892    * @param array The array to convert.  Must not be <jk>null</jk> (a <jk>null</jk> argument throws {@link NullPointerException}).
1893    * @param elementType
1894    *    The type of objects in the array.
1895    *    It must match the actual component type in the array.
1896    * @return A new {@link ArrayList}
1897    */
1898   public static <E> List<E> toList(Object array, Class<E> elementType) {
1899      var l = new ArrayList<E>(Array.getLength(array));
1900      for (var i = 0; i < Array.getLength(array); i++)
1901         l.add((E)Array.get(array, i));
1902      return l;
1903   }
1904
1905   /**
1906    * Recursively converts the specified array into a list of objects.
1907    *
1908    * @param array The array to convert.  Must not be <jk>null</jk> (a <jk>null</jk> argument throws {@link NullPointerException}).
1909    * @return A new {@link ArrayList}
1910    */
1911   public static List<Object> toObjectList(Object array) {
1912      var l = new ArrayList<>(Array.getLength(array));
1913      for (var i = 0; i < Array.getLength(array); i++) {
1914         var o = Array.get(array, i);
1915         if (ClassUtils.isArray(o))
1916            o = toObjectList(o);
1917         l.add(o);
1918      }
1919      return l;
1920   }
1921
1922   /**
1923    * Creates a new set from the specified collection.
1924    *
1925    * @param <E> The element type.
1926    * @param val The value to copy from.
1927    * @return A new {@link LinkedHashSet}, or <jk>null</jk> if the input was null.
1928    */
1929   public static <E> Set<E> toSet(Collection<E> val) {
1930      return val == null ? null : new LinkedHashSet<>(val);
1931   }
1932
1933   /**
1934    * Converts the specified array to a <c>Set</c>.
1935    *
1936    * <p>
1937    * The order of the entries in the set are the same as the array.
1938    *
1939    * @param <T> The entry type of the array.
1940    * @param array The array being wrapped in a <c>Set</c> interface.  Must not be <jk>null</jk> (a <jk>null</jk> argument throws {@link IllegalArgumentException}).
1941    * @return The new set.
1942    */
1943   public static <T> Set<T> toSet(T[] array) {
1944      reqnn("array", array);
1945      return new AbstractSet<>() {
1946
1947         @Override /* Overridden from Set */
1948         public Iterator<T> iterator() {
1949            return new Iterator<>() {
1950               int i = 0;
1951
1952               @Override /* Overridden from Iterator */
1953               public boolean hasNext() {
1954                  return i < array.length;
1955               }
1956
1957               @Override /* Overridden from Iterator */
1958               public T next() {
1959                  if (i >= array.length)
1960                     throw new NoSuchElementException();
1961                  T t = array[i];
1962                  i++;
1963                  return t;
1964               }
1965
1966               @Override /* Overridden from Iterator */
1967               public void remove() {
1968                  throw uoex();
1969               }
1970            };
1971         }
1972
1973         @Override /* Overridden from Set */
1974         public int size() {
1975            return array.length;
1976         }
1977      };
1978   }
1979
1980   //-----------------------------------------------------------------------------------------------------------------
1981   // Primitive array creation methods
1982   //-----------------------------------------------------------------------------------------------------------------
1983
1984   /**
1985    * Creates a new {@link TreeSet} from the specified collection.
1986    *
1987    * @param <E> The element type.
1988    * @param value The value to copy from.
1989    * @return A new {@link TreeSet}, or an empty {@link TreeSet} if the input was <jk>null</jk>.
1990    */
1991   public static <E> SortedSet<E> toSortedSet(Collection<E> value) {
1992      if (value == null)
1993         return new TreeSet<>();
1994      var l = new TreeSet<E>();
1995      value.forEach(l::add);
1996      return l;
1997   }
1998
1999   /**
2000    * Creates a new {@link TreeSet} from the specified collection.
2001    *
2002    * @param <E> The element type.
2003    * @param value The value to copy from.
2004    * @param nullIfEmpty If <jk>true</jk> returns <jk>null</jk> if the collection is empty.
2005    * @return A new {@link TreeSet}, or an empty {@link TreeSet} if the input was <jk>null</jk>, or <jk>null</jk> if nullIfEmpty and the collection is empty.
2006    */
2007   public static <E> SortedSet<E> toSortedSet(Collection<E> value, boolean nullIfEmpty) {
2008      if (value == null)
2009         return new TreeSet<>();
2010      if (nullIfEmpty && value.isEmpty())
2011         return null;
2012      var l = new TreeSet<E>();
2013      value.forEach(l::add);
2014      return l;
2015   }
2016
2017   /**
2018    * Creates a new {@link TreeSet} containing a copy of the specified set.
2019    *
2020    * @param <T> The element type.
2021    * @param copyFrom The set to copy from.
2022    * @return A new {@link TreeSet}, or an empty {@link TreeSet} if the input was <jk>null</jk>.
2023    */
2024   public static <T> SortedSet<T> toSortedSet(Set<T> copyFrom) {
2025      return copyFrom == null ? new TreeSet<>() : new TreeSet<>(copyFrom);
2026   }
2027
2028   /**
2029    * Converts an array to a stream of objects.
2030    * @param array The array to convert.  Must not be <jk>null</jk> (a <jk>null</jk> or non-array argument throws {@link IllegalArgumentException}).
2031    * @return A new stream.
2032    */
2033   public static Stream<Object> toStream(Object array) {
2034      req(ClassUtils.isArray(array), "Arg was not an array.  Type: %s", ClassUtils.className(array));
2035      var length = Array.getLength(array);
2036      return IntStream.range(0, length).mapToObj(i -> Array.get(array, i));
2037   }
2038
2039   /**
2040    * Converts the specified collection to an array of strings.
2041    *
2042    * <p>
2043    * Entries are converted to strings using {@link #toString()}.
2044    * <jk>null</jk> values remain <jk>null</jk>.
2045    *
2046    * @param c The collection to convert.  Must not be <jk>null</jk>.
2047    * @return The collection as a string array.
2048    */
2049   public static String[] toStringArray(Collection<?> c) {
2050      var r = new String[c.size()];
2051      var i = 0;
2052      for (var o : c)
2053         r[i++] = stringify(o);
2054      return r;
2055   }
2056
2057   /**
2058    * Traverses all elements in the specified object and executes a consumer for each leaf.
2059    *
2060    * <p>
2061    * Input shapes are processed as follows:
2062    * <ul>
2063    *    <li><b>Flattened (recursively):</b> {@link Iterable}, {@link Stream}, and any array type (including all 8 primitive
2064    *       array types via {@link ClassUtils#isArray}), including arbitrary nesting and mixing of these.
2065    *    <li><b>Leaf (consumer called once):</b> anything else — {@link String}, {@link Map}, custom beans, boxed primitives, etc.
2066    *    <li><b>{@code null} handling:</b> a {@code null} root, or {@code null} encountered mid-traversal, causes the
2067    *       consumer to be called zero times — no {@code null} elements are ever delivered.
2068    * </ul>
2069    *
2070    * @param <T> The element type.
2071    * @param o The object to traverse.  Can be <jk>null</jk> (the consumer is not called).
2072    * @param c The consumer of the leaf elements.  Must not be <jk>null</jk>.
2073    */
2074   public static <T> void traverse(Object o, Consumer<T> c) {
2075      CollectionUtils.<T>traverseToStream(o).forEach(c);
2076   }
2077
2078   /**
2079    * Shared recursive engine for {@link #traverse(Object, Consumer)}, {@link #accumulate(Object...)}, and
2080    * {@link #deepStream(Object...)}.
2081    *
2082    * <p>
2083    * Returns a lazily-evaluated {@link Stream} that recursively flattens {@link Iterable}, {@link Stream}, and
2084    * array inputs (including all primitive array types), treating everything else as a single leaf element.
2085    * {@code null} inputs return an empty stream.
2086    */
2087   private static <T> Stream<T> traverseToStream(Object o) {
2088      if (o == null)
2089         return Stream.empty();
2090      if (o instanceof Iterable<?> o2)
2091         return StreamSupport.stream(o2.spliterator(), false).flatMap(CollectionUtils::traverseToStream);
2092      if (o instanceof Stream<?> o2)
2093         return o2.flatMap(CollectionUtils::traverseToStream);
2094      if (ClassUtils.isArray(o))
2095         return toStream(o).flatMap(CollectionUtils::traverseToStream);
2096      return Stream.of((T)o);
2097   }
2098
2099   //-----------------------------------------------------------------------------------------------------------------
2100   // Stream utilities
2101   //-----------------------------------------------------------------------------------------------------------------
2102
2103   //-----------------------------------------------------------------------------------------------------------------
2104   // Full-named factory/query methods (canonical forms; short-named methods delegate to these)
2105   //-----------------------------------------------------------------------------------------------------------------
2106
2107   /**
2108    * Creates an array of objects (varargs form).
2109    *
2110    * @param <T> The component type of the array.
2111    * @param x The objects to place in the array.  Can be <jk>null</jk> (returned as-is).
2112    * @return A new array containing the specified objects.
2113    */
2114   @SafeVarargs
2115   public static <T> T[] array(T...x) {
2116      return x;
2117   }
2118
2119   /**
2120    * Creates a 2-dimensional array.
2121    *
2122    * @param <E> The element type of the inner arrays.
2123    * @param value The 1D arrays that will become rows in the 2D array.  Can be <jk>null</jk> (returned as-is).
2124    * @return A 2D array containing the specified rows.
2125    */
2126   @SafeVarargs
2127   public static <E> E[][] array2d(E[]...value) {
2128      return value;
2129   }
2130
2131   /**
2132    * Creates an Object array.
2133    *
2134    * @param value The objects to place in the array.  Can be <jk>null</jk> (returned as-is).
2135    * @return A new {@code Object[]} containing the specified objects.
2136    */
2137   public static Object[] objectArray(Object...value) {
2138      return value;
2139   }
2140
2141   /**
2142    * Returns null for the specified array type.
2143    *
2144    * <p>Intentional null return for assertion testing.
2145    *
2146    * @param <T> The component type.
2147    * @param type The component type class.
2148    * @return <jk>null</jk>.
2149    */
2150   public static <T> T[] nullArray(Class<T> type) {
2151      return null;
2152   }
2153
2154   /**
2155    * Creates a LinkedList from the specified values.
2156    *
2157    * @param <T> The element type.
2158    * @param values The values to add to the list.  Must not be <jk>null</jk> (a <jk>null</jk> array throws {@link NullPointerException}).
2159    * @return A new modifiable LinkedList containing the specified values.
2160    */
2161   @SafeVarargs
2162   public static <T> List<T> linkedList(T...values) {
2163      return new LinkedList<>(fixedSizeList(values));
2164   }
2165
2166   /**
2167    * Creates a HashSet from the specified values.
2168    *
2169    * @param <T> The element type.
2170    * @param values The values to add to the set.  Must not be <jk>null</jk> (a <jk>null</jk> array throws {@link NullPointerException}).
2171    * @return A new modifiable HashSet containing the specified values.
2172    */
2173   @SafeVarargs
2174   public static <T> Set<T> hashSet(T...values) {
2175      return new HashSet<>(Arrays.asList(values));
2176   }
2177
2178   /**
2179    * Creates an unmodifiable view of the specified list.
2180    *
2181    * @param <T> The element type.
2182    * @param value The list to make unmodifiable. Can be null.
2183    * @return An unmodifiable view of the list, or null if the input was null.
2184    */
2185   public static <T> List<T> unmodifiable(List<? extends T> value) {
2186      return value == null ? null : Collections.unmodifiableList(value);
2187   }
2188
2189   /**
2190    * Creates an unmodifiable view of the specified map.
2191    *
2192    * @param <K> The key type.
2193    * @param <V> The value type.
2194    * @param value The map to make unmodifiable. Can be null.
2195    * @return An unmodifiable view of the map, or null if the input was null.
2196    */
2197   public static <K,V> Map<K,V> unmodifiable(Map<? extends K,? extends V> value) {
2198      return value == null ? null : Collections.unmodifiableMap(value);
2199   }
2200
2201   /**
2202    * Creates an unmodifiable view of the specified set.
2203    *
2204    * @param <T> The element type.
2205    * @param value The set to make unmodifiable. Can be null.
2206    * @return An unmodifiable view of the set, or null if the input was null.
2207    */
2208   public static <T> Set<T> unmodifiable(Set<? extends T> value) {
2209      return value == null ? null : Collections.unmodifiableSet(value);
2210   }
2211
2212   /**
2213    * Creates an unmodifiable view of the specified sorted set.
2214    *
2215    * @param <T> The element type.
2216    * @param value The sorted set to make unmodifiable. Can be null.
2217    * @return An unmodifiable view of the sorted set, or null if the input was null.
2218    */
2219   public static <T> SortedSet<T> unmodifiable(SortedSet<T> value) {
2220      return value == null ? null : Collections.unmodifiableSortedSet(value);
2221   }
2222
2223   /**
2224    * Returns the element at the specified index, wrapped in an {@link Optional}.
2225    *
2226    * @param <E> The element type.
2227    * @param l The list. Can be <jk>null</jk>.
2228    * @param index The index to access.
2229    * @return An Optional containing the element, or an empty Optional if null/out-of-bounds.
2230    */
2231   public static <E> Optional<E> optionalAt(List<E> l, int index) {
2232      return Optional.ofNullable(elementAt(l, index));
2233   }
2234
2235   /**
2236    * Returns <jk>null</jk> if the specified map is <jk>null</jk> or empty, otherwise returns the map.
2237    *
2238    * @param <K> The key type.
2239    * @param <V> The value type.
2240    * @param val The map to check.
2241    * @return <jk>null</jk> if the map is <jk>null</jk> or empty, otherwise the map itself.
2242    */
2243   public static <K,V> Map<K,V> nullIfEmpty(Map<K,V> val) {
2244      return isEmpty(val) ? null : val;
2245   }
2246
2247   /**
2248    * Returns <jk>null</jk> if the specified list is <jk>null</jk> or empty, otherwise returns the list.
2249    *
2250    * @param <E> The element type.
2251    * @param val The list to check.
2252    * @return <jk>null</jk> if the list is <jk>null</jk> or empty, otherwise the list itself.
2253    */
2254   public static <E> List<E> nullIfEmpty(List<E> val) {
2255      return isEmpty(val) ? null : val;
2256   }
2257
2258   /**
2259    * Returns <jk>null</jk> if the specified set is <jk>null</jk> or empty, otherwise returns the set.
2260    *
2261    * @param <E> The element type.
2262    * @param val The set to check.
2263    * @return <jk>null</jk> if the set is <jk>null</jk> or empty, otherwise the set itself.
2264    */
2265   public static <E> Set<E> nullIfEmpty(Set<E> val) {
2266      return isEmpty(val) ? null : val;
2267   }
2268
2269   /**
2270    * Returns <jk>true</jk> if the specified collection is not null and not empty.
2271    *
2272    * @param c The collection to check.
2273    * @return <jk>true</jk> if not null and not empty.
2274    */
2275   public static boolean isNotEmpty(Collection<?> c) {
2276      return c != null && ! c.isEmpty();
2277   }
2278
2279   /**
2280    * Returns <jk>true</jk> if the specified map is not null and not empty.
2281    *
2282    * @param m The map to check.
2283    * @return <jk>true</jk> if not null and not empty.
2284    */
2285   public static boolean isNotEmpty(Map<?,?> m) {
2286      return m != null && ! m.isEmpty();
2287   }
2288
2289   /**
2290    * Returns the element at the specified index.
2291    *
2292    * @param <E> The element type.
2293    * @param l The list. Can be null.
2294    * @param index The index to access.
2295    * @return The element, or null if out-of-bounds/null list.
2296    */
2297   public static <E> E elementAt(List<E> l, int index) {
2298      if (l == null || index < 0 || index >= l.size())
2299         return null;
2300      return l.get(index);
2301   }
2302
2303   /**
2304    * Creates a new modifiable LinkedHashSet.
2305    *
2306    * @param <T> The element type.
2307    * @param values The values to add to the set.  Must not be <jk>null</jk> (a <jk>null</jk> array throws {@link IllegalArgumentException}).
2308    * @return A modifiable LinkedHashSet containing the specified values.
2309    */
2310   @SafeVarargs
2311   public static <T> Set<T> set(T...values) {
2312      reqnn("values", values);
2313      return new LinkedHashSet<>(Arrays.asList(values));
2314   }
2315
2316   /**
2317    * Creates an int array.
2318    *
2319    * @param value The values.
2320    * @return A new int array.
2321    */
2322   public static int[] intArray(int...value) { return value; }
2323
2324   /**
2325    * Creates a long array.
2326    *
2327    * @param value The values.
2328    * @return A new long array.
2329    */
2330   public static long[] longArray(long...value) { return value; }
2331
2332   /**
2333    * Creates a byte array from ints.
2334    *
2335    * @param value The int values to convert to bytes.
2336    * @return A new byte array.
2337    */
2338   public static byte[] byteArray(int...value) {
2339      var result = new byte[value.length];
2340      for (var i = 0; i < value.length; i++)
2341         result[i] = (byte)value[i];
2342      return result;
2343   }
2344
2345   /**
2346    * Creates a char array.
2347    *
2348    * @param value The values.
2349    * @return A new char array.
2350    */
2351   public static char[] charArray(char...value) { return value; }
2352
2353   /**
2354    * Creates a float array.
2355    *
2356    * @param value The values.
2357    * @return A new float array.
2358    */
2359   public static float[] floatArray(float...value) { return value; }
2360
2361   /**
2362    * Creates a double array.
2363    *
2364    * @param value The values.
2365    * @return A new double array.
2366    */
2367   public static double[] doubleArray(double...value) { return value; }
2368
2369   /**
2370    * Creates a boolean array.
2371    *
2372    * @param value The values.
2373    * @return A new boolean array.
2374    */
2375   public static boolean[] booleanArray(boolean...value) { return value; }
2376
2377   /**
2378    * Creates a short array from ints.
2379    *
2380    * @param value The int values to convert to shorts.
2381    * @return A new short array.
2382    */
2383   public static short[] shortArray(int...value) {
2384      var result = new short[value.length];
2385      for (var i = 0; i < value.length; i++)
2386         result[i] = (short)value[i];
2387      return result;
2388   }
2389
2390   private CollectionUtils() {}
2391}