javacollectionssequence

Java Collections API: missing a Sequence (ordered Collection) super-interface of List and Deque?


I need to expose an API - consume(sequence) below - which mandates that its argument sequence collection be ordered as in the below excerpt:

interface Consumer<T> {
    /**
     * @param sequence: an *ordered* collection of Ts to be processed in order
     */
    public void consume(Collection<T> sequence);
}

interface Producer<T> {
    Collection<T> getSequence();
}

class Producer1<T> implements Producer<T> {
    public List<T> getSequence() {
        return new ArrayList<>();
    }
}
class Producer2<T> implements Producer<T> {
    public Deque<T> getSequence() {
        return new LinkedList<>();
    }
}

class Test {
    void testMethod(Consumer<Long> consumer) {
        consumer.consume(new Producer1<Long>().getSequence());
        consumer.consume(new Producer2<Long>().getSequence());
    }
}

Typically one would specify consume() as accepting a List; however, some producers also expose a Deque, so as to facilitate things like efficient reverse-iteration using descendingIterator(). However Deque doesn't extend List and there are likely good reasons for this (O(n) cost of accessing an indexed element in a LinkedList).

So it seems the only way to "keep the compiler happy" is to specify sequence as a Collection; however, according to the Javadoc (and as we all know), a "some are ordered and others unordered", so the consume() API looses in semantics.

Another workaround would be to have Producer2 expose a LinkedList rather than a Deque (and revert consume() to accept a List) but we know it's not ideal to expose implementations rather than interfaces.

It seems the ideal solution would be for Java to provide a Sequence super-interface to List and Deque (extending Iterable). I can imagine one reason this wasn't done is complexity but I think this example demonstrates the need.

Am I missing a better strategy here or do I just need to wait for a revision of the API? For the record, this is Java 17.


Solution

  • JEP 431: Sequenced Collections

    As predicted in the Answer by Rob Spoor, Sequenced Collections were delivered in Java 21. See JEP 431 for details.

    You wanted a standard interface that would cover both List & Deque as representing a sequence.

    Now you have it. In Java 21 and later, SequencedCollection is a super-interface with both List & Deque as sub-interfaces. So concrete classes such as ArrayList, LinkedList, and ArrayDeque can all be referred to as a SequencedCollection.

    SequencedCollection<String> x = new ArrayList<>() ;
    SequencedCollection<String> y = new LinkedList<>() ;
    SequencedCollection<String> z = new ArrayDeque<>() ;
    

    Specific to your Question, you can now declare your consume method as taking a SequencedCollection rather than the more general Collection.

    public void consume( SequencedCollection<T> sequence );
    

    Those classes gained new features. All implementations of SequencedCollection offer methods to add, get, and remove elements from the first and last positions. They also offer a reversed method to iterate in opposite order.

    For more info, see excellent presentation by Stuart Marks, the lead on JEP 431. Here is his class diagram:

    diagram of Java Collection Framework class hierarchy with SequencedCollection added