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