Core Java

Sequenced Collections in Java 21

Java has continuously evolved to meet the changing needs of developers. One area of constant improvement is the collections framework, which provides a set of classes and interfaces to store and manipulate groups of objects. Starting from JDK 21, JEP 431 introduces three Java Collections Framework interfaces for creating sequenced collections, sequenced sets, and sequenced maps. These features simplify interacting with collections that have a defined order, enhancing code readability and reducing boilerplate. This article will explore what Sequenced Collections offer and how they elevate our Java coding experience.

1. Understanding Sequenced Collections

The need to introduce sequenced interfaces stems from a longstanding request for easy methods to retrieve a collection’s first and last elements. Before JDK 21, Java Collections Framework didn’t have a collection type representing a sequence with a specific order.

Java 21 introduces three new interfaces:

  • SequencedCollection
  • SequencedSet
  • SequencedMap

These interfaces provide a uniform API for:

  • Accessing first and last elements: No more searching or iterating just to grab the head or tail.
  • Adding/removing elements at both ends: Push and pop operations become cleaner and more intuitive.
  • Iterating in reverse: Get a reversed view of the collection with a single method call.

2. Getting Started with Sequenced Collections

Sequenced Collections are seamlessly integrated into existing APIs. Most existing collection classes like List and Deque already implement the relevant interfaces. This means we can start reaping the benefits without extensive code changes.

2.1 SequencedCollection

SequencedCollection represents any collection with a defined order. It provides a standardized way to access and manipulate elements at both the beginning and end of a collection. 

The SequencedCollection interface provides methods for adding, retrieving, and removing elements from both ends along with a method named reversed() which provides a reverse-ordered view of the original collection.

2.1.1 Example

public class SequencedCollectionExamples {

    public static void main(String[] args) {

        SequencedCollection<String> sequencedCollection = new ArrayList<>();

        sequencedCollection.add("Send Email"); // List contains [Send Email] 

        sequencedCollection.addFirst("Fix Bug"); // List contains [Fix Bug, Send Email] 

        sequencedCollection.addLast("Write Report"); // List contains [Fix Bug, Send Email, Write Report]

        System.out.println("" + sequencedCollection);

        String firstElement = sequencedCollection.getFirst();  
        String lastElement = sequencedCollection.getLast();  

        System.out.println("" + firstElement); // Fix Bug
        System.out.println("" + lastElement); // Write Report

        SequencedCollection reversed = sequencedCollection.reversed();
        System.out.println(reversed); // Prints [Write Report, Send Email, Fix Bug]

    }
}

The output from running the code above is:

Fig 1: Sequenced Collection example output
Fig 1: Sequenced Collection example output

2.2 SequencedSet

SequencedSet extends SequencedCollection and guarantees unique elements in the order they were added. The SequencedSet interface is designed for Set implementations like LinkedHashSet and SortedSet.

Key features include:

  • Unique elements: No duplicates allowed.
  • Defined order: Elements have a specific encounter order, from first to last.
  • Reversed view: You can get a reversed view of the set with reversed() method.
  • Methods for accessing and manipulating elements at both ends.

2.2.1 Example

public class SequencedSetExample {

    public static void main(String[] args) {
        
        SequencedSet<String> uniqueNames = new LinkedHashSet<>();

        uniqueNames.add("Charles");
        uniqueNames.add("Thomas");
        uniqueNames.add("Dickson");

        String firstElement = uniqueNames.getFirst();   
        String lastElement = uniqueNames.getLast();    
        
        System.out.println("" + firstElement); // Charles
        System.out.println("" + lastElement); // Dickson

        uniqueNames.addFirst("Sarah"); 
        System.out.println("" + uniqueNames); // Set contains: [Sarah, Charles, Thomas, Dickson]
        
        uniqueNames.addLast("Bill"); 
        System.out.println("" + uniqueNames); // Set contains: [Sarah, Charles, Thomas, Dickson, Bill]

        System.out.println(uniqueNames.reversed());   //Prints [Bill, Dickson, Thomas, Charles, Sarah]
    }
}

In the code above:

  • We use the getFirst() method to get the first element. Note that the program will throw a NoSuchElementException if the collection is empty.
  • To get the last element, we use the getLast() method. 
  • To add a value as the first element, we use the addFirst() method. Note that If the value already exists, it will be removed as the first element.
  • To add a value as the last element, we use the addLast() method.
  • uniqueNames.reversed() method is used to reverse the order of the elements.

2.3 SequencedMap

SequencedMap is an interface that extends Map and provides a standardized way to work with maps that have a defined encounter order for their entries.

SequencedMap‘s are reversible and the reverse order of the map is typically not serializable, even if the original map is.

Key features include:

  • Encounter order for entries: Remembers the sequence in which key-value pairs were added.
  • Methods for accessing and manipulating entries at both ends: Offers methods like putFirst() and putLast() for efficient manipulation of the map’s ends.
  • Reversed view: Provides a reversed view of the map’s entries with reversed() method.
  • Sequenced views for keys, values, and entries: Offers sequencedKeys(), sequencedValues(), and sequencedEntrySet() methods for accessing views that respect the encounter order.

2.3.1 Example

public class SequencedMapExample {

    public static void main(String[] args) {

        SequencedMap<String, Integer> scores = new LinkedHashMap<>();
        scores.put("John", 95);
        scores.put("Omos", 82);
        scores.put("James", 72);

        System.out.println("" + scores.firstEntry()); // John=95 (prints the value of the first entry)
        System.out.println("" + scores.lastEntry()); // James=72 (prints the value of the last entry)

        System.out.println(scores); // prints {John=95, Omos=82, James=72}

        SequencedMap.Entry<String, Integer> first = scores.pollFirstEntry();   
        SequencedMap.Entry<String, Integer> last = scores.pollLastEntry();    

       
        System.out.println("Map contains: " + scores); // prints {Omos=82}

        scores.putFirst("Jerry", 75);     
        scores.putLast("Sarah", 80);    

        System.out.println(scores);  // {Jerry=75, Omos=82, Sarah=80}
        System.out.println(scores.reversed());   // {Sarah=80, Omos=82, Jerry=75}

    }
}

In the code above:

  • The first entry of the map is obtained by using the firstEntry() method.
  • To get the last entry of the map, we use the lastEntry() method.
  • The putFirst() method is used to put an entry as the first one.
  • The putLast() method is used to put an entry as the last one.
  • To get and remove the first entry, we use the pollFirstEntry() method.
  • To get and remove the last entry, we use the pollLastEntry() method.
  • The order of the entries is reversed by using the reversed() method. 

3. Key Points

  • Most existing ordered collections implicitly implement SequencedCollection, so we can often cast them to use the new methods.
  • SequencedCollection offers a consistent API for working with the beginning and end of collections, simplifying common tasks and improving code readability.
  • SequencedSet and SequencedMap provide additional features for unique elements and key-value pairs, respectively, while maintaining order.
  • Most existing ordered collections like List and Deque already implement the appropriate interfaces.

4. Conclusion

The introduction of Sequenced Collections in Java 21 marks a significant improvement for developers working with ordered collections. By offering a consistent and intuitive API, this feature boosts code readability, reduces boilerplate, and unlocks new possibilities for building efficient and expressive Java applications.

5. Download the Source Code

This was an example of Sequenced Collections in Java 21.

Download
You can download the full source code of this example here: Sequenced Collections in Java 21

Omozegie Aziegbe

Omos holds a Master degree in Information Engineering with Network Management from the Robert Gordon University, Aberdeen. Omos is currently a freelance web/application developer who is currently focused on developing Java enterprise applications with the Jakarta EE framework.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button