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<Map<String,Object>>[] <jv>data</jv> = <jk>new</jk> List[]{ 058 * <jk>new</jk> ArrayList<>(Arrays.asList( 059 * <jk>new</jk> LinkedHashMap<>(){{ 060 * put(<js>"name"</js>, <js>"John"</js>); 061 * put(<js>"age"</js>, 30); 062 * }} 063 * )), 064 * <jk>new</jk> ArrayList<>(Arrays.asList( 065 * <jk>new</jk> LinkedHashMap<>(){{ 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<Map<String,Object>>[] <jv>complex</jv> = <jk>new</jk> List[]{ 087 * <jk>new</jk> ArrayList<>(Arrays.asList( 088 * <jk>new</jk> LinkedHashMap<>(){{ 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<>(){{ 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<>(Arrays.asList( 098 * <jk>new</jk> LinkedHashMap<>(){{ 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<Object> <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<Object> <jv>result</jv> = <jsm>accumulate</jsm>(<jv>nested</jv>); 158 * 159 * <jc>// Multi-root: returns [1, 2, "a", "b"]</jc> 160 * List<Object> <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<Object> <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<String> <jv>list</jv> = <jk>new</jk> ArrayList<>(); 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<String> <jv>set</jv> = <jk>new</jk> LinkedHashSet<>(); 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<String> <jv>it</jv> = list.iterator(); 525 * Optional<String> <jv>first</jv> = <jsm>next</jsm>(<jv>it</jv>); <jc>// Optional.of("first")</jc> 526 * Optional<String> <jv>second</jv> = <jsm>next</jsm>(<jv>it</jv>); <jc>// Optional.of("second")</jc> 527 * Optional<String> <jv>empty</jv> = <jsm>next</jsm>(<jv>it</jv>); <jc>// Optional.empty()</jc> 528 * Optional<String> <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<String> <jv>list</jv> = <jsm>l</jsm>(<js>"a"</js>, <js>"b"</js>, <js>"c"</js>); 550 * Optional<String> <jv>first</jv> = <jsm>first</jsm>(<jv>list</jv>); <jc>// Optional.of("a")</jc> 551 * 552 * Set<Integer> <jv>set</jv> = <jsm>s</jsm>(1, 2, 3); 553 * Optional<Integer> <jv>firstInt</jv> = <jsm>first</jsm>(<jv>set</jv>); <jc>// Optional.of(1) or another element</jc> 554 * 555 * EnumSet<MyEnum> <jv>enumSet</jv> = EnumSet.allOf(MyEnum.<jk>class</jk>); 556 * Optional<MyEnum> <jv>firstEnum</jv> = <jsm>first</jsm>(<jv>enumSet</jv>); <jc>// Optional.of(first enum value)</jc> 557 * 558 * Optional<String> <jv>empty</jv> = <jsm>first</jsm>(Collections.emptyList()); <jc>// Optional.empty()</jc> 559 * Optional<String> <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<String,Object> <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<String,Object> <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<String,Object> <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<String> <jv>list</jv> = <jsm>list</jsm>(<js>"a"</js>, <js>"b"</js>, <js>"c"</js>); 1522 * Stream<String> <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<String> <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<String> <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<String> <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<String,Integer> <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<String> <jv>myQueue</jv> = new LinkedList<>(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}