Interface Selection<T>


public interface Selection<T>
An immutable selection of choices for implementing allowlists or denylists, supporting both limited and unlimited selections.

Useful when you need to disambiguate and enforce correct handling of the implicitly selected all concept, in replacement of the common and error prone empty-means-all hack. That is, instead of adding (or forgetting to add) special handling like:


   Set<String> choices = getChoices();
   if (choices.isEmpty() || choices.contains("foo")) {
     // foo is selected.
   }
 
Use Selection so your code is intuitive and hard to get wrong:

   Selection<String> choices = getChoices();
   if (choices.has("foo")) {
     // foo is selected.
   }
 

To gradually migrate from legacy code where empty sets need to be special handled all over, use nonEmptyOrAll(set) to convert to a Selection object:


   public class FoodDeliveryService {
     private final Selection<Driver> eligibleDrivers;

     // Too much code churn to change this public constructor signature.
     public FoodDeliveryService(Set<Driver> eligibleDrivers) {
       // But we can migrate internal implementation to using Selection:
       this.eligibleDrivers = Selection.nonEmptyOrAll(eligibleDrivers);
     }

     ...
   }
 

While an unlimited selection is conceptually close to a trivially-true predicate, the Selection type provides access to the explicitly selected choices via the limited() method. It also implements equals(java.lang.Object), hashCode() and toString() sensibly.

Nulls are prohibited throughout this class.

Since:
8.0
  • Method Details

    • all

      static <T> Selection<T> all()
      Returns an unlimited selection of all (unspecified) choices.
    • none

      static <T> Selection<T> none()
      Returns an empty selection.
    • only

      @SafeVarargs static <T> Selection<T> only(T... choices)
      Returns a selection of choices. Null is not allowed.
    • nonEmptyOrAll

      static <T> Selection<T> nonEmptyOrAll(Collection<? extends T> choices)
      Converts to Selection from legacy code where an empty collection means all. After converted to Selection, user code no longer need special handling of the empty case.

      This method is mainly for migrating legacy code. If you have a set where empty just means "none" with no special handling needed, you should use set.stream().collect(toSelection()) instead.

    • toSelection

      static <T> Collector<T,?,Selection<T>> toSelection()
      Returns a collector that collects input elements into a limited selection.
    • toIntersection

      static <T> Collector<Selection<T>,?,Selection<T>> toIntersection()
      Returns a collector that intersects the input selections.
    • toUnion

      static <T> Collector<Selection<T>,?,Selection<T>> toUnion()
      Returns a collector that unions the input selections.
    • parser

      static Selection.Parser parser()
      Returns the default parser, using ',' as delimiter of elements.
      Since:
      4.7
    • delimitedBy

      static Selection.Parser delimitedBy(char delimiter)
      Returns a parser for Selection, using the delimiter character to delimit explicit selection elements.

      Because '*' is used as special indicator of all(), it can't be used as the delimiter.

      Since:
      4.7
    • delimitedBy

      static Selection.Parser delimitedBy(Substring.Pattern delimiter)
      Returns a parser for Selection, using the delimiter patter to delimit explicit selection elements.

      Because '*' is used as special indicator of all(), it can't be used as the delimiter.

      Since:
      4.7
    • has

      boolean has(T candidate)
      Returns true if candidate is in this selection.
    • isEmpty

      boolean isEmpty()
      Returns true if this is a limited selection with zero elements included. For example: Selection.none().
    • limited

      Optional<Set<T>> limited()
      Returns the limited choices if this selection is a limited instance; Optional.empty() for unlimited instances.

      Note that limited() returning Optional.empty() vs. returning Optional.of(emptySet()) have completely different semantics: the former means the selection is unlimited (or, has no limit); while the latter indicates that the selection has zero choices, i.e., none().

      The caller can use this method to optionally handle explicit choices, for example:

      
         Selection<Region> requestedRegions = ...;
         requestedRegions.limited().ifPesent(this::checkValidRegions);
       
    • intersect

      Selection<T> intersect(Selection<T> that)
      Returns an intersection of this selection and that.
    • intersect

      Selection<T> intersect(Set<? extends T> set)
      Returns an intersection of this selection and the elements from set.
    • union

      Selection<T> union(Selection<T> that)
      Returns an union of this selection and that.
    • union

      Selection<T> union(Set<? extends T> set)
      Returns a union of this selection and the elements from set.
    • equals

      boolean equals(Object obj)
      Returns true if obj is an equivalent Selection instance. Specifically:
      • unlimited is always equal to itself, while never equal to any limited selections (even if the limited selection includes all known choices).
      • Two limited selections are equal if they represent equal set of explicit choices. The set order doesn't matter, that is, [a, b] is considered to be equal to [b, a].
      Overrides:
      equals in class Object
    • hashCode

      int hashCode()
      Overrides:
      hashCode in class Object
    • toString

      String toString()
      Returns "ALL" if unlimited, or else returns the string representation of the set of the explicit choices. That is, only("dog", "cat").toString() will return "[dog, cat]".
      Overrides:
      toString in class Object