001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.commons.collections; 018 019import static java.util.Collections.*; 020import static org.apache.juneau.commons.utils.ClassUtils.*; 021import static org.apache.juneau.commons.utils.Shorts.*; 022 023import java.lang.reflect.*; 024import java.util.*; 025import java.util.function.*; 026 027/** 028 * A fluent builder for constructing {@link Set} instances with various configuration options. 029 * 030 * <p> 031 * This builder provides a flexible and type-safe way to construct sets with support for adding elements, 032 * collections, arrays, sorting, and applying modifiers like unmodifiable or sparse modes. Sets automatically 033 * handle duplicates - adding the same element multiple times will result in only one occurrence in the final set. 034 * 035 * <h5 class='section'>Features:</h5> 036 * <ul class='spaced-list'> 037 * <li>Fluent API - all methods return <c>this</c> for method chaining 038 * <li>Multiple add methods - single elements, varargs, collections, arrays 039 * <li>Arbitrary input support - automatic type conversion with {@link #addAny(Object...)} 040 * <li>Conditional adding - {@link #addIf(boolean, Object)} for conditional elements 041 * <li>Sorting support - natural order or custom {@link Comparator} 042 * <li>Sparse mode - return <jk>null</jk> for empty sets 043 * <li>Unmodifiable mode - create immutable sets 044 * <li>Filtering support - exclude unwanted elements via {@link #filtered()} or {@link #filtered(Predicate)} 045 * <li>Custom conversion functions - type conversion via {@link #elementFunction(Function)} 046 * <li>Automatic deduplication - duplicate elements are automatically removed 047 * </ul> 048 * 049 * <h5 class='section'>Examples:</h5> 050 * <p class='bjava'> 051 * <jc>// Basic usage</jc> 052 * Set<String> <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 053 * .add(<js>"apple"</js>, <js>"banana"</js>, <js>"cherry"</js>) 054 * .build(); 055 * 056 * <jc>// Automatic deduplication</jc> 057 * Set<Integer> <jv>unique</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>) 058 * .add(1, 2, 3, 2, 1) <jc>// Duplicates ignored</jc> 059 * .build(); <jc>// Contains: 1, 2, 3</jc> 060 * 061 * <jc>// With sorting</jc> 062 * Set<String> <jv>sorted</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 063 * .add(<js>"zebra"</js>, <js>"apple"</js>, <js>"banana"</js>) 064 * .sorted() 065 * .build(); <jc>// Returns TreeSet in natural order</jc> 066 * 067 * <jc>// Conditional elements</jc> 068 * Set<String> <jv>features</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 069 * .add(<js>"basic"</js>) 070 * .addIf(<jv>hasPremium</jv>, <js>"premium"</js>) 071 * .addIf(<jv>hasEnterprise</jv>, <js>"enterprise"</js>) 072 * .build(); 073 * 074 * <jc>// Immutable set</jc> 075 * Set<String> <jv>immutable</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 076 * .add(<js>"read"</js>, <js>"only"</js>) 077 * .unmodifiable() 078 * .build(); 079 * 080 * <jc>// From multiple sources</jc> 081 * Set<Integer> <jv>existing</jv> = Set.of(1, 2, 3); 082 * Set<Integer> <jv>combined</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>) 083 * .addAll(<jv>existing</jv>) 084 * .add(4, 5, 6) 085 * .build(); 086 * 087 * <jc>// Sparse mode - returns null when empty</jc> 088 * Set<String> <jv>maybeNull</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 089 * .sparse() 090 * .build(); <jc>// Returns null, not empty set</jc> 091 * 092 * <jc>// FluentSet wrapper - use buildFluent()</jc> 093 * FluentSet<String> <jv>fluent</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 094 * .add(<js>"one"</js>, <js>"two"</js>) 095 * .buildFluent(); 096 * 097 * <jc>// FilteredSet - use buildFiltered()</jc> 098 * FilteredSet<Integer> <jv>filtered</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>) 099 * .filtered(v -> v > 0) 100 * .add(5) 101 * .add(-1) <jc>// Filtered out</jc> 102 * .buildFiltered(); 103 * </p> 104 * 105 * <h5 class='section'>Thread Safety:</h5> 106 * <p> 107 * This class is <b>not thread-safe</b>. Each builder instance should be used by a single thread or 108 * properly synchronized. 109 * 110 * <h5 class='section'>See Also:</h5><ul> 111 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsCollections">Collections Package</a> 112 * <li class='jc'>{@link Lists} 113 * <li class='jc'>{@link Maps} 114 * </ul> 115 * 116 * @param <E> The element type. 117 */ 118@SuppressWarnings({ 119 "java:S1168", // build() and buildFiltered() return null when sparse() is set and the set is empty 120 "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants 121 "java:S3740", // Raw Set/Iterable types used in utility methods where element type is not statically known 122 "unchecked" // Element casts such as (E)o in the builder are guarded by the builder's element-type contract 123}) 124public class Sets<E> { 125 126 /** 127 * Static creator. 128 * 129 * @param <E> The element type. 130 * @param elementType The element type. Must not be <jk>null</jk>. 131 * @return A new builder. 132 */ 133 public static <E> Sets<E> create(Class<E> elementType) { 134 return new Sets<>(reqnn("elementType", elementType)); 135 } 136 137 private Set<E> set; 138 private boolean unmodifiable; 139 private boolean sparse; 140 private boolean concurrent; 141 private boolean ordered = false; 142 143 private Comparator<E> comparator; 144 private Predicate<E> filter; 145 private Class<E> elementType; 146 private Function<Object,E> elementFunction; 147 148 /** 149 * Constructor. 150 * 151 * @param elementType The element type. Must not be <jk>null</jk>. 152 */ 153 public Sets(Class<E> elementType) { 154 this.elementType = reqnn("elementType", elementType); 155 } 156 157 /** 158 * Adds a single value to this set. 159 * 160 * <p> 161 * Note: Filtering is applied at build time, not when adding elements. 162 * 163 * @param value The value to add to this set. 164 * @return This object. 165 */ 166 public Sets<E> add(E value) { 167 if (set == null) { 168 if (ordered) 169 set = new LinkedHashSet<>(); 170 else if (nn(comparator)) 171 set = new TreeSet<>(comparator); 172 else 173 set = new HashSet<>(); 174 } 175 set.add(value); 176 return this; 177 } 178 179 /** 180 * Adds multiple values to this set. 181 * 182 * @param values The values to add to this set. 183 * @return This object. 184 */ 185 public Sets<E> add(E...values) { 186 reqnn("values", values); 187 for (var v : values) 188 add(v); 189 return this; 190 } 191 192 /** 193 * Appends the contents of the specified collection into this set. 194 * 195 * <p> 196 * This is a no-op if the value is <jk>null</jk>. 197 * 198 * @param value The collection to add to this set. 199 * @return This object. 200 */ 201 public Sets<E> addAll(Collection<E> value) { 202 if (nn(value)) { 203 if (set == null) { 204 if (ordered) 205 set = new LinkedHashSet<>(value); 206 else if (nn(comparator)) 207 set = new TreeSet<>(comparator); 208 else 209 set = new HashSet<>(value); 210 } else { 211 set.addAll(value); 212 } 213 } 214 return this; 215 } 216 217 /** 218 * Adds arbitrary values to this set. 219 * 220 * <p> 221 * Objects can be any of the following: 222 * <ul> 223 * <li>The same type or convertible to the element type of this set. 224 * <li>Collections or arrays of anything on this set. 225 * <li>JSON array strings parsed and convertible to the element type of this set. 226 * </ul> 227 * 228 * @param values The values to add. 229 * @return This object. 230 */ 231 @SuppressWarnings({ 232 "java:S3776" // Cognitive complexity acceptable for adding elements of various types 233 }) 234 public Sets<E> addAny(Object...values) { 235 if (nn(values)) { 236 for (var o : values) { 237 if (nn(o)) { 238 if (o instanceof Collection<?> o2) { 239 o2.forEach(this::addAny); 240 } else if (isArray(o)) { 241 for (var i = 0; i < Array.getLength(o); i++) 242 addAny(Array.get(o, i)); 243 } else if (elementType.isInstance(o)) { 244 add(elementType.cast(o)); 245 } else { 246 E converted = convertElement(o); 247 if (converted != null) { 248 add(converted); 249 } else { 250 throw rex("Object of type %s could not be converted to type %s", cn(o), cn(elementType)); 251 } 252 } 253 } 254 } 255 } 256 return this; 257 } 258 259 /** 260 * Adds a value to this set if the specified flag is true. 261 * 262 * @param flag The flag. 263 * @param value The value. 264 * @return This object. 265 */ 266 public Sets<E> addIf(boolean flag, E value) { 267 if (flag) 268 add(value); 269 return this; 270 } 271 272 /** 273 * Adds entries to this set via JSON array strings. 274 * 275 * @param values The JSON array strings to parse and add to this set. 276 * @return This object. 277 */ 278 public Sets<E> addJson(String...values) { 279 return addAny((Object[])values); 280 } 281 282 /** 283 * Builds the set. 284 * 285 * <p> 286 * Applies filtering, sorting, ordering, concurrent, unmodifiable, and sparse options. 287 * 288 * <p> 289 * Set type selection: 290 * <ul> 291 * <li>If {@link #sorted()} is set: Uses {@link TreeSet} (or synchronized TreeSet if concurrent) 292 * <li>If {@link #ordered()} is set: Uses {@link LinkedHashSet} (or synchronized LinkedHashSet if concurrent) 293 * <li>Otherwise: Uses {@link HashSet} (or synchronized HashSet if concurrent) 294 * </ul> 295 * 296 * <p> 297 * If filtering is applied, the result is wrapped in a {@link FilteredSet}. 298 * 299 * @return The built set, or {@code null} if {@link #sparse()} is set and the set is empty. 300 */ 301 public Set<E> build() { 302 if (sparse && ie(set)) 303 return null; 304 305 Set<E> set2 = null; 306 307 if (ordered) { 308 set2 = new LinkedHashSet<>(); 309 } else if (nn(comparator)) { 310 set2 = new TreeSet<>(comparator); 311 } else { 312 set2 = new HashSet<>(); 313 } 314 315 if (concurrent) 316 set2 = synchronizedSet(set2); 317 318 if (nn(filter) || nn(elementFunction)) { 319 var set3b = FilteredSet.create(elementType); 320 if (nn(filter)) 321 set3b.filter(filter); 322 if (nn(elementFunction)) 323 set3b.elementFunction(elementFunction); 324 set2 = set3b.inner(set2).build(); 325 } 326 327 if (nn(set)) 328 set2.addAll(set); 329 330 if (unmodifiable) 331 set2 = unmodifiableSet(set2); 332 333 return set2; 334 } 335 336 /** 337 * Builds the set and wraps it in a {@link FluentSet}. 338 * 339 * <p> 340 * This is a convenience method that calls {@link #build()} and wraps the result in a {@link FluentSet}. 341 * 342 * <h5 class='section'>Example:</h5> 343 * <p class='bjava'> 344 * <jk>import static</jk> org.apache.juneau.commons.utils.CollectionUtils.*; 345 * 346 * FluentSet<String> <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 347 * .add(<js>"one"</js>, <js>"two"</js>) 348 * .buildFluent(); 349 * </p> 350 * 351 * @return The built set wrapped in a {@link FluentSet}, or {@code null} if {@link #sparse()} is set and the set is empty. 352 */ 353 public FluentSet<E> buildFluent() { 354 Set<E> result = build(); 355 return result == null ? null : new FluentSet<>(result); 356 } 357 358 /** 359 * Builds the set as a {@link FilteredSet}. 360 * 361 * <p> 362 * Set type selection: 363 * <ul> 364 * <li>If {@link #sorted()} is set: Uses {@link TreeSet} (or synchronized TreeSet if concurrent) 365 * <li>If {@link #ordered()} is set: Uses {@link LinkedHashSet} (or synchronized LinkedHashSet if concurrent) 366 * <li>Otherwise: Uses {@link HashSet} (or synchronized HashSet if concurrent) 367 * </ul> 368 * 369 * <h5 class='section'>Example:</h5> 370 * <p class='bjava'> 371 * <jk>import static</jk> org.apache.juneau.commons.utils.CollectionUtils.*; 372 * 373 * FilteredSet<Integer> <jv>set</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>) 374 * .filtered(v -> v != <jk>null</jk> && v > 0) 375 * .add(5) 376 * .add(-1) <jc>// Will be filtered out</jc> 377 * .buildFiltered(); 378 * </p> 379 * 380 * <p> 381 * Note: If {@link #unmodifiable()} is set, the returned set will be wrapped in an unmodifiable view, 382 * which may cause issues if the FilteredSet tries to modify it internally. It's recommended to avoid 383 * using {@link #unmodifiable()} when calling this method. 384 * 385 * @return The built set as a {@link FilteredSet}, or {@code null} if {@link #sparse()} is set and the set is empty. 386 */ 387 public FilteredSet<E> buildFiltered() { 388 var s = build(); 389 if (s == null) // sparse mode and empty 390 return null; 391 if (s instanceof FilteredSet<E> s2) 392 return s2; 393 // Note that if unmodifiable is true, 's' will be unmodifiable and will cause an error if you try 394 // to insert a value from within FilteredSet. 395 return FilteredSet.create(elementType).inner(s).build(); 396 } 397 398 /** 399 * Sets the element conversion function for converting elements in {@link #addAny(Object...)}. 400 * 401 * <p> 402 * The function is applied to each element when adding elements in {@link #addAny(Object...)}. 403 * 404 * @param elementFunction The function to convert elements. Must not be <jk>null</jk>. 405 * @return This object. 406 */ 407 public Sets<E> elementFunction(Function<Object,E> elementFunction) { 408 this.elementFunction = reqnn("elementFunction", elementFunction); 409 return this; 410 } 411 412 /** 413 * Specifies the element type on this list. 414 * 415 * @param value The element type. Must not be <jk>null</jk>. 416 * @return This object. 417 */ 418 public Sets<E> elementType(Class<E> value) { 419 elementType = reqnn("value", value); 420 return this; 421 } 422 423 /** 424 * Applies a default filter that excludes common "empty" or "unset" values from being added to the set. 425 * 426 * <p> 427 * The following values are filtered out: 428 * <ul> 429 * <li>{@code null} 430 * <li>{@link Boolean#FALSE} 431 * <li>Numbers with {@code intValue() == -1} 432 * <li>Empty arrays 433 * <li>Empty {@link Map Maps} 434 * <li>Empty {@link Collection Collections} 435 * </ul> 436 * 437 * <h5 class='section'>Example:</h5> 438 * <p class='bjava'> 439 * <jk>import static</jk> org.apache.juneau.commons.utils.CollectionUtils.*; 440 * 441 * Set<Object> <jv>set</jv> = Sets.<jsm>create</jsm>(Object.<jk>class</jk>) 442 * .filtered() 443 * .add(<js>"name"</js>) 444 * .add(-1) <jc>// Filtered out at build time</jc> 445 * .add(<jk>false</jk>) <jc>// Filtered out at build time</jc> 446 * .add(<jk>new</jk> String[0]) <jc>// Filtered out at build time</jc> 447 * .build(); 448 * </p> 449 * 450 * @return This object. 451 */ 452 public Sets<E> filtered() { 453 // @formatter:off 454 return filtered(v -> ! ( 455 v == null 456 || (v instanceof Boolean v2 && v2.equals(false)) 457 || (v instanceof Number v3 && v3.intValue() == -1) 458 || (isArray(v) && Array.getLength(v) == 0) 459 || (v instanceof Map v2 && v2.isEmpty()) 460 || (v instanceof Collection v3 && v3.isEmpty()) 461 )); 462 // @formatter:on 463 } 464 465 /** 466 * Applies a filter predicate to elements when building the set. 467 * 468 * <p> 469 * The filter receives the element value. Elements where the predicate returns 470 * {@code true} will be kept; elements where it returns {@code false} will be filtered out. 471 * 472 * <p> 473 * This method can be called multiple times. When called multiple times, all filters are combined 474 * using AND logic - an element must pass all filters to be kept in the set. 475 * 476 * <p> 477 * Note: Filtering is applied at build time, not when adding elements. 478 * 479 * <h5 class='section'>Example:</h5> 480 * <p class='bjava'> 481 * <jk>import static</jk> org.apache.juneau.commons.utils.CollectionUtils.*; 482 * 483 * <jc>// Keep only non-null, positive integers</jc> 484 * Set<Integer> <jv>set</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>) 485 * .filtered(v -> v != <jk>null</jk> && v > 0) 486 * .add(5) 487 * .add(-1) <jc>// Filtered out at build time</jc> 488 * .add(<jk>null</jk>) <jc>// Filtered out at build time</jc> 489 * .build(); 490 * 491 * <jc>// Multiple filters combined with AND</jc> 492 * Set<Integer> <jv>set2</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>) 493 * .filtered(v -> v != <jk>null</jk>) <jc>// First filter</jc> 494 * .filtered(v -> v > 0) <jc>// Second filter (ANDed with first)</jc> 495 * .filtered(v -> v < 100); <jc>// Third filter (ANDed with previous)</jc> 496 * .add(5) 497 * .add(150) <jc>// Filtered out (not < 100)</jc> 498 * .add(-1) <jc>// Filtered out (not > 0)</jc> 499 * .build(); 500 * </p> 501 * 502 * @param filter The filter predicate. Must not be <jk>null</jk>. 503 * @return This object. 504 */ 505 public Sets<E> filtered(Predicate<E> filter) { 506 Predicate<E> newFilter = reqnn("filter", filter); 507 if (this.filter == null) 508 this.filter = newFilter; 509 else 510 this.filter = this.filter.and(newFilter); 511 return this; 512 } 513 514 /** 515 * Converts the set into a {@link SortedSet}. 516 * 517 * <p> 518 * Note: If {@link #ordered()} was previously called, calling this method will override it. 519 * The last method called ({@link #ordered()} or {@link #sorted()}) determines the final set type. 520 * 521 * @return This object. 522 */ 523 public Sets<E> sorted() { 524 return sorted((Comparator<E>)Comparator.naturalOrder()); 525 } 526 527 /** 528 * Converts the set into a {@link SortedSet} using the specified comparator. 529 * 530 * <p> 531 * Note: If {@link #ordered()} was previously called, calling this method will override it. 532 * The last method called ({@link #ordered()} or {@link #sorted()}) determines the final set type. 533 * 534 * @param comparator The comparator to use for sorting. Must not be <jk>null</jk>. 535 * @return This object. 536 */ 537 public Sets<E> sorted(Comparator<E> comparator) { 538 this.comparator = reqnn("comparator", comparator); 539 ordered = false; 540 return this; 541 } 542 543 /** 544 * When specified, the {@link #build()} method will return <jk>null</jk> if the set is empty. 545 * 546 * <p> 547 * Otherwise {@link #build()} will never return <jk>null</jk>. 548 * 549 * @return This object. 550 */ 551 public Sets<E> sparse() { 552 sparse = true; 553 return this; 554 } 555 556 557 /** 558 * When specified, {@link #build()} will return an unmodifiable set. 559 * 560 * @return This object. 561 */ 562 public Sets<E> unmodifiable() { 563 unmodifiable = true; 564 return this; 565 } 566 567 /** 568 * When specified, {@link #build()} will return a thread-safe synchronized set. 569 * 570 * <p> 571 * The thread-safety implementation depends on other settings: 572 * <ul> 573 * <li>If {@link #sorted()} is set: Uses synchronized {@link TreeSet} 574 * <li>If {@link #ordered()} is set: Uses synchronized {@link LinkedHashSet} 575 * <li>Otherwise: Uses synchronized {@link HashSet} 576 * </ul> 577 * 578 * <p> 579 * This is useful when the set needs to be accessed from multiple threads. 580 * 581 * <h5 class='section'>Example:</h5> 582 * <p class='bjava'> 583 * <jc>// Create a thread-safe set using synchronized HashSet</jc> 584 * Set<String> <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 585 * .add(<js>"one"</js>, <js>"two"</js>) 586 * .concurrent() 587 * .build(); 588 * 589 * <jc>// Create a thread-safe ordered set</jc> 590 * Set<String> <jv>set2</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 591 * .ordered() 592 * .concurrent() 593 * .add(<js>"one"</js>) 594 * .build(); 595 * </p> 596 * 597 * @return This object. 598 */ 599 public Sets<E> concurrent() { 600 concurrent = true; 601 return this; 602 } 603 604 /** 605 * Sets whether {@link #build()} should return a thread-safe synchronized set. 606 * 607 * <p> 608 * The thread-safety implementation depends on other settings: 609 * <ul> 610 * <li>If {@link #sorted()} is set: Uses synchronized {@link TreeSet} 611 * <li>If {@link #ordered()} is set: Uses synchronized {@link LinkedHashSet} 612 * <li>Otherwise: Uses synchronized {@link HashSet} 613 * </ul> 614 * 615 * <p> 616 * This is useful when the set needs to be accessed from multiple threads. 617 * 618 * <h5 class='section'>Example:</h5> 619 * <p class='bjava'> 620 * <jc>// Conditionally create a thread-safe set</jc> 621 * Set<String> <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 622 * .add(<js>"one"</js>, <js>"two"</js>) 623 * .concurrent(<jv>needsThreadSafety</jv>) 624 * .build(); 625 * </p> 626 * 627 * @param value Whether to make the set thread-safe. 628 * @return This object. 629 */ 630 public Sets<E> concurrent(boolean value) { 631 concurrent = value; 632 return this; 633 } 634 635 /** 636 * When specified, {@link #build()} will use a {@link LinkedHashSet} to preserve insertion order. 637 * 638 * <p> 639 * If not specified, a {@link HashSet} is used by default (no guaranteed order). 640 * 641 * <p> 642 * Note: If {@link #sorted()} was previously called, calling this method will override it. 643 * The last method called ({@link #ordered()} or {@link #sorted()}) determines the final set type. 644 * 645 * <h5 class='section'>Example:</h5> 646 * <p class='bjava'> 647 * <jc>// Create an ordered set (preserves insertion order)</jc> 648 * Set<String> <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 649 * .ordered() 650 * .add(<js>"one"</js>) 651 * .add(<js>"two"</js>) 652 * .build(); 653 * </p> 654 * 655 * @return This object. 656 */ 657 public Sets<E> ordered() { 658 return ordered(true); 659 } 660 661 /** 662 * Sets whether {@link #build()} should use a {@link LinkedHashSet} to preserve insertion order. 663 * 664 * <p> 665 * If <c>false</c> (default), a {@link HashSet} is used (no guaranteed order). 666 * If <c>true</c>, a {@link LinkedHashSet} is used (preserves insertion order). 667 * 668 * <p> 669 * Note: If {@link #sorted()} was previously called, calling this method with <c>true</c> will override it. 670 * The last method called ({@link #ordered()} or {@link #sorted()}) determines the final set type. 671 * 672 * <h5 class='section'>Example:</h5> 673 * <p class='bjava'> 674 * <jc>// Conditionally create an ordered set</jc> 675 * Set<String> <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>) 676 * .ordered(<jv>preserveOrder</jv>) 677 * .add(<js>"one"</js>) 678 * .build(); 679 * </p> 680 * 681 * @param value Whether to preserve insertion order. 682 * @return This object. 683 */ 684 public Sets<E> ordered(boolean value) { 685 ordered = value; 686 if (ordered) 687 comparator = null; 688 return this; 689 } 690 691 /** 692 * Converts an element object to the element type. 693 * 694 * @param o The object to convert. 695 * @return The converted element, or <jk>null</jk> if conversion is not possible. 696 */ 697 private E convertElement(Object o) { 698 if (elementType.isInstance(o)) 699 return (E)o; 700 if (nn(elementFunction)) 701 return elementFunction.apply(o); 702 return null; 703 } 704}