Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8037382

The Collections framework needs a Sequence and SequenceSet interface



    • Enhancement
    • Resolution: Duplicate
    • P4
    • None
    • 8
    • core-libs


      There are cases where client code needs assurance that a collection retains its order of insertion, but does not need the additional methods of the list interface, and retains correctness if duplicates are not allowed. Currently such code must specify a java.util.Collection and then contain a comment that it must either be given a java.util.List or java.util.LinkedHashSet. It would be much better if such code could specify that it accepts a Sequence. For completeness a SequenceSet (set that is also a sequence such as LinkedHashSet) and SequenceMap (map that is also a sequence such as LinkedHashMap) should also be defined.

      The usecase that has prompted this request is: A security method that enforces roles based on regular expressions in order of regular expressions (so if the first one matches, the rest are not processed). Such a method does not care if the backing class is a List or LinkedHashSet, only that the order of the elements are preserved. In fact using the java.util.List interface for such a method is undesirable as java.util.LinkedHashMap would prevent undesirable redundant processing from happening by eliminating duplicates.

      SequenceSet and SequenceMap are not strictly necessary (LinkedHashSet and LinkedHashMap can be specified instead), but it is a better programming practice for a client to specify an interface that has the desired behavioral contract than to specify a concrete implementation class. Adding SequenceSet and SequenceMap will allow for alternative implementations of these concepts to be freely used. It also gives a sane return value for LinkedHashMap's keySet() and entrySet() methods which should return collections that are both sets and sequences.

      EXPECTED -
      Add the following three interfaces in package java.util:
      Sequence<T> extends Collection<T>;
      SequenceSet<T> extends Sequence<T>, Set<T>;
      SequenceMap<K,V> extends Map<K,V>. SequenceMap would have the following body:

      interface SequenceMap<K,V> extends Map<K,V> {
           SequenceSet<K> keySet();
           Sequence<V> values();
           SequenceSet<Map.Entry<K,V>> entrySet();

      Make the following changes to the collections framework:

      List<T> extends Sequence<T>;
      LinkedHashSet<T> implements SequenceSet<T>;
      LinkedHashMap implements SequenceMap<T>;

      The objects returned by LinkedHashMap's keySet(), values(), and entrySet() would be changed to implement the Sequence and SequenceSet interfaces per the SequenceMap interface.

      More formally: A Sequence guarantees that an iteration will produce the elements in the same order and quantity as Sequence.add(T) returns true, but Sequence.add(T) may or may not refuse duplicate elements.

      A SequenceSet makes the same guarantee as a Sequence and additionally guarantees that there will not exist two elements a and b such that a.equals(b) (the Set contract).

      A SequenceMap guarantees that an iteration on the map will produce the elements in the same order as the last insertion of a given key.

      This should remain 100% compatible with existing Java code.

      ACTUAL -
      Methods that need assurance that collection items are in a sequence have the following two alternatives:

      1. specify that their property is a java.util.Collection, document that they really want either a java.util.List or java.util.LinkedHashSet and hope for the best. This obviously invites bad behavior if elements are inserted into a HashSet and then processed.

      2. Overload the property setter with one that accepts a java.util.List, and another that accepts a java.util.LinkedHashSet. Although cumbersome, this is reasonable for a write-only property. However, this does not work for bean properties that are readable and writable. When the readable property is a java.util.Collection, then a setter for java.util.Collection must also exist which defeats the purpose of the setter overloading.

      ---------- BEGIN SOURCE ----------
      import java.util.*;

      public class SequenceDemo {

      final List<String> sequenceList = Arrays.asList("1","2","3");

      static public void main(String[] args) {
      SequenceDemo demo = new SequenceDemo();

      public void demo() {
      processSequence(new LinkedHashSet<>(sequenceList));
      // Uh-oh... this one will fail.
      processSequence(new HashSet<>(sequenceList));

      public <T extends Comparable<? super T>> void processSequence(Collection<T> sequence) {
      if (!sequence.isEmpty()) {
      Iterator<T> i = sequence.iterator();
      T a = i.next();
      while(i.hasNext()) {
      T b = i.next();
      if (a.compareTo(b) > 0) {
      throw new IllegalArgumentException("Class " + sequence.getClass().getSimpleName() + " has elements out of order.");
      ---------- END SOURCE ----------

      Defining an internal attribute as a java.util.Collection, and then overloading a setter with java.util.List and java.util.LinkedHashMap for writeonly properties. For readable and writable properties, the only "workaround" is to use java.util.Collection which has the issue demonstrated in the executable test case (e.g. that a HashSet is a valid parameter).


        Issue Links



              smarks Stuart Marks
              webbuggrp Webbug Group
              0 Vote for this issue
              2 Start watching this issue