Saturday, 31 January 2015

Java collection framework

This article talks about the collection framework in Java. Interfaces and classes hierarchy for collections:



This hierarchy is missing the Deque interface which extends Queue and it is a double direction Queue.

List


The interface 'List' cares about the index as the elements are ordered by index. Three classes implement this interface:
  • ArrayList: it is very fast during the iteration as it is not synchronized for thread safety.
  • Vector: same than 'ArrayList' except that it is an older version (introduced in Java 2) and it is slower as it is synchronized for thread safety.
  • LinkedList: it is fast for adding or removing elements in the collection; you can add or remove from the beginning or the end which makes 'LinkedList' a good candidate to implement a stack or a queue; note that it also implements 'Queue' interface.
    // Declaration of a List of strings
    List stringsList = new ArrayList();

    // We add strings elements to the list
    stringsList.add("Jean");
    stringsList.add("Julie");
    stringsList.add("Julie");        // Ok, duplicate allowed
    stringsList.add("Sandrine");
    stringsList.add("Alain");
    stringsList.add("Alexandre");

    System.out.println("- The list contains '"+stringsList.size()+"' elements.");
   
    // We check if 'Sandrine' is in the list
    if(stringsList.contains("Sandrine")){
       
        // We get the index of the element 'Sandrine'
       int indexOfSandrine = stringsList.indexOf("Sandrine");
       
        System.out.println("- The String element with the value 'Sandrine' is in the list at position "+indexOfSandrine);
       
        // We get 'Sandrine' object by index
        String sandrine = stringsList.get(indexOfSandrine);
       
        // We remove Sandrine by index
        if(stringsList.remove(indexOfSandrine) instanceof String){
            System.out.println("- 'Sandrine' removed.");
        }
    }

    // We remove 'Jean' by 'object'
    if(stringsList.remove("Jean")){
        System.out.println("- 'Jean' removed.");
    }

    System.out.println("- The list contains '"+stringsList.size()+"' elements.");

    // We iterate through the list
    System.out.println("- Elements:");
    for(String element : stringsList){
        System.out.println("  - "+element);
    }
Output:
- The list contains '6' elements.
- The String element with the value 'Sandrine' is in the list at position 3
- 'Sandrine' removed.
- 'Jean' removed.
- The list contains '4' elements.
- Elements:
   - Julie
   - Julie
   - Alain
   - Alexandre


Set


The interface 'Set' cares about uniqueness of each element. It does not allow duplicates, it checks if 2 elements are equal by using their methods 'equals()'.
Three classes implement this interface:
  • HashSet: it is an unsorted and an unordered 'Set'. It uses the 'hashCode()' to store and locate the elements. Use this class if the order of the elements does not matter when you iterate through them.
  • LinkedHashSet: it is an ordered version of 'HashSet'. The elements are ordered in function of their insertion order.
  • TreeSet: it is a sorted Set. By default it sorts the elements in natural order. You can modify this behaviour by defining a custom 'Comparable' or 'Comparator' objects.
Note that "TreeSet" implements the interface "NavigableSet".
    // Declaration of a Set of strings
   Set stringsSet = new HashSet();

    // We add strings elements to the collection
    stringsSet.add("Jean");
    stringsSet.add("Julie");
    stringsSet.add("Julie");     // Nope, duplicate not allowed in a 'Set'; this returns 'false'
    stringsSet.add("Sandrine");
    stringsSet.add("Alain");
    stringsSet.add("Alexandre");

    System.out.println("- The Set contains '"+stringsSet.size()+"' elements.");

    // We check if 'Sandrine' is in the list
    if(stringsSet.contains("Sandrine")){
       
        System.out.println("- The String element with the value 'Sandrine' is in the Set collection");
       
        // We remove Sandrine by object
        if(stringsSet.remove("Sandrine")){
            System.out.println("- 'Sandrine' removed.");
        }
    }

    System.out.println("- The Set contains '"+stringsSet.size()+"' elements.");

    // We iterate through the list
    System.out.println("- Elements:");
    for(String element : stringsSet){
        System.out.println("  - "+element);
    }

Output:
- The Set contains '5' elements.
- The String element with the value 'Sandrine' is in the Set collection
- 'Sandrine' removed.
- The Set contains '4' elements.
- Elements:
   - Alain
   - Jean
   - Alexandre
   - Julie


Map


The interface 'Map' cares about the identifier or key associated with each values (objects) to store. It relies on 'hashCode()' and 'equals()' methods to check that each key is identical.
Four classes implement this interface:
  • HashMap: it is an unsorted and unordered 'Map'. It uses the 'hashCode()' to store and locate the keys. It allows to set one 'null' key and many 'null' values. Use this class if the order of the elements does not matter when you iterate through them.
  • LinkedHashMap: it is an ordered version of 'HashMap'. The elements are ordered in function of their insertion order. It uses the 'hashCode()' to store and locate the keys.
  • Hashtable: same than 'HashMap' except that it is older version (introduced in Java 2) and it is slower as it is synchronized for thread safety.
  • TreeMap: it is a sorted 'Map'. By default it sorts the elements in natural order. You can modify this behaviour by defining a custom 'Comparable' or 'Comparator' objects.
Note that "TreeMap" implements the interface "NavigableMap".

Definition of the class 'Person':
    class Person {
        public String firstName;
        public String lastName;
        public int age;
   
        Person(String firstName, String lastName, int age){
            this.firstName = firstName;
            this.lastName = lastName;
            this.age = age;
        }
    }
Usage of a 'Map':
    // Declaration of a Map collection in which we map each person's name to her associated 'Person' object
    Map stringsMap = new HashMap();

    // We add elements to the collection
    stringsMap.put("Jean", new Person("Jean", "Valjean", 52));
    stringsMap.put("Julie", new Person("Julie", "Bourgeon", 26));
   stringsMap.put("Julie", new Person("Julie", "Delavier", 40));         // Override the Person object of the previous key "Julie"
    stringsMap.put("Sandrine", new Person("Sandrine", "LaBelle", 28));
    stringsMap.put("Alain", new Person("Alain", "Boulanger", 49));
    stringsMap.put("Alexandre", new Person("Alexandre", "Dupain", 30));

    System.out.println("- The Map contains '"+stringsMap.size()+"' elements.");

    // We get a Person object by key
    Person sandrine = stringsMap.get("Sandrine");

    // We check if 'Sandrine' is in the list
    if(stringsMap.containsKey("Sandrine") && stringsMap.containsValue(sandrine)){

        System.out.println("- The String element with the key 'Sandrine' is in the Map collection");

        // We remove Sandrine by key
        if(stringsMap.remove("Sandrine") instanceof Person){
            System.out.println("- 'Sandrine' removed.");
        }
    }

    System.out.println("- The Map contains '"+stringsMap.size()+"' elements.");

    // We iterate through the list
    System.out.println("- Elements:");
    for(Map.Entry entry : stringsMap.entrySet()) {
        System.out.println("  - "+entry.getKey()+" ("+entry.getValue().age+" years old)");
    }
Output:
- The Map contains '5' elements.
- The String element with the key 'Sandrine' is in the Map collection
- 'Sandrine' removed.
- The Map contains '4' elements.
- Elements:
   - Alain (49 years old)
   - Jean (52 years old)
   - Alexandre (30 years old)
   - Julie (40 years old)