Collection

The Collection is a Java API for storing several references of the same type. It is easy to understand if you think that similar to an array but much more convenient.

The following figure shows the hierarchical relationship of the collection's primary interfaces.

Collection Framework

Consider the following when choosing a collection class. A collection class is either a Set interface implementation, a List interface implementation, or a Map interface implementation.

  • Set does not allow duplication, and there is no order in it.
  • List does allow duplication, and there is an order in it.
  • Map stores data in the form of keys and values.

Here are the frequently used collection classes:

Interface Implementation(after Java 2) Implementation(before Java 2)
Set HashSet
TreeSet
List ArrayList Vector
LinkedList
Map HashMap Properties
TreeMap

Set

The following example shows how to use the Set interface.
Create a HashSet and add the name using the add method of the Set interface.
The following example attempts to add "Bill" in duplicate. But you can see from the output that this item did not go into the HashSet.

SetExample.java
package net.java_school.collection;

import java.util.*;

public class SetExample {
  public static void main(String args[]) {
	  
    Set<String> set = new HashSet<String>();
    set.add("Bill");
    set.add("Elsa");
    set.add("Debbie");
    set.add("Alison");
    set.add("Carol");
    set.add("Bill");
		    
    System.out.println(set);//you can not add something in duplicate to a Set.
		    
    Set<String> sortedSet = new TreeSet<String>(set);
    System.out.println(sortedSet);//the list is sorted.
  }
}
C:\ Command Prompt
C:\java\Collection\bin>java net.java_school.collection.SetExample
[Elsa, Alison, Carol, Bill, Debbie]
[Alison, Bill, Carol, Debbie, Elsa]

If you look in the Java documentation for the collection class covered in the example, you can see the <E>, <T>, <K, V> in the class declaration. These interfaces, abstract classes, and classes are called generic. -- Java 5 introduced Generics -- E means Element, T means Type, K means Key, and V means Value. You can use these symbols to declare unspecified data types. These data types are determined at runtime, not compile time.

The following example creates a generic account number for the account class.

package net.java_school.collection;

public class Account<T> {
	
  private T accountNo;//AccountNo can be any type.
	
  public T getAccountNo() {
    return accountNo;
  }

  public void setAccountNo(T accountNo) {
    this.accountNo = accountNo;
  }

  public static void main(String[] args) {
    Account<String> ac1 = null;
    ac1 = new Account<String>();// The account number data type is determined by String.
    ac1.setAccountNo("111-222-333");
		
    Account<Integer> ac2 = null;
    ac2 = new Account<Integer>();// The account number data type is determined by Integer.
    ac2.setAccountNo(111222333);// See below for the wrapper class
  }
}

List

The List inherits the Collection interface, has an order and allows duplicates, and has an index address starting from 0 like an array.

The ArrayList is the most popular class in the List family.
The following example shows the usage of ArrayList.

ArrayListExample.java
package net.java_school.collection;

import java.util.ArrayList;

public class ArrayListExample {

  public static void main(String[] args) {
    ArrayList<String> a = new ArrayList<String>();
		
    a.add("Tom");
    a.add("Jerry");
		
    String hong = a.get(1);
    System.out.println(hong);
		
    //Enhanced For-Loops
    for (String name : a) {
      System.out.print(name +"\t");
    }
  }
}
C:\ Command Prompt
C:\java\Collection\bin>java net.java_school.collection.ArrayListExample
Jerry
Tom		Jerry

The following example compares the usage of ArrayList and LinkedList.

ListExample.java
package net.java_school.collection;

import java.util.*;

public class ListExample {
  public static void main(String args[]) {
    List<String> list = new ArrayList<String>();
		    
    list.add("A");
    list.add("B");
    list.add("C");
    list.add("D");
    list.add("E");
		
    System.out.println(list);
    System.out.println("2: " + list.get(2));
    System.out.println("0: " + list.get(0));
		
    LinkedList<String> linkedList = new LinkedList<String>();
		
    linkedList.addFirst("A");
    linkedList.addFirst("B");
    linkedList.addFirst("C");
    linkedList.addFirst("D");
    linkedList.addFirst("E");
		    
    System.out.println(linkedList);
    linkedList.removeLast();
    linkedList.removeLast();
		    
    System.out.println(linkedList);
  }
}
C:\ Command Prompt
C:\java\Collection\bin>java net.java_school.collection.ListExample
[A, B, C, D, E]
2: C
0: A
[E, D, C, B, A]
[E, D, C]

Map

Map stores data in pairs of keys and values.
The following example uses a HashMap and later changes the HashMap to a TreeMap which sorts data by key value.

MapExample.java
package net.java_school.collection;

import java.util.*;

public class MapExample {
  public static void main(String args[]) {
	
    Map<String,String> map = new HashMap<String,String>();
		
    map.put("1", "Bill");
    map.put("2", "Elsa");
    map.put("3", "Debbie");
    map.put("4", "Alison");
    map.put("5", "Carol");
		
    System.out.println(map);
    System.out.println(map.get("4"));
		
    Map<String,String> sortedMap = new TreeMap<String,String>(map);
    System.out.println(sortedMap);
  }
}
C:\ Command Prompt
C:\java\Collection\bin>java net.java_school.collection.MapExample
{3=Debbie, 2=Elsa, 1=Bill, 5=Carol, 4=Alison}
Alison
{1=Bill, 2=Elsa, 3=Debbie, 4=Alison, 5=Carol}

Let's modify the above example using Wrapper classes. The Integer is a Wrapper class corresponding to an int data type. Even if you use Integer type key values, the HashMap sorts data.

MapExample.java
package net.java_school.collection;

import java.util.*;

public class MapExample {
  public static void main(String args[]) {
	
    Map<Integer,String> map = new HashMap<Integer,String>();
		
    map.put(1, "Bill");
    map.put(2, "Elsa");
    map.put(3, "Debbie");
    map.put(4, "Alison");
    map.put(5, "Carol");
		
    System.out.println(map);
    System.out.println(map.get(4));
		
    Map<Integer,String> sortedMap = new TreeMap<Integer,String>(map);
    System.out.println(sortedMap);
  }
}
C:\ Command Prompt
C:\java\Collection\bin>java net.java_school.collection.MapExample
{1=Bill, 2=Elsa, 3=Debbie, 4=Alison, 5=Carol}
Alison
{1=Bill, 2=Elsa, 3=Debbie, 4=Alison, 5=Carol}

Vector

Vector and ArrayList are a big difference.
Vector is thread-safe, whereas ArrayList is not thread-safe.
There are a lot of performance differences between thread-safe and non-thread-safe, so you need a good reason for choosing thread-safe ones.
Note: The JDBC connection pooling code covered in JDBC uses a thread-safe Vector.
The following example shows the usage of Vector.

VectorExample.java
package net.java_school.collection;

import java.util.*;

public class VectorExample {
  public static void main(String[] args) {
	
    Vector<String> v = new Vector<String>();
	
    for (int i = 0; i < 10; i++) {
      v.addElement(String.valueOf(Math.random() * 100));
    }
		
    for (int i = 0; i < 10; i++) {
      System.out.println(v.elementAt(i));
    }
  }
}
C:\ Command Prompt
C:\java\Collection\bin>java net.java_school.collection.VectorExample
64.93767837163008
1.7024404924644077
56.445592597123806
23.41304656773643
92.55620070095163
41.6525553754475
47.39373268828609
83.84855063525016
67.34657837510855
41.04715452201211

Properties

Properties is a popular class for reading values from configuration files in Java. Properties stores data in pairs of keys and values.

PropertiesStore.java

package net.java_school.collection;

import java.util.*;
import java.io.*;

public class PropertiesStore {
  public static void main(String[] args) {
	
    Properties prop = new Properties();
    prop.put("title", "Back in Black");
    prop.put("singer", "AC/DC");
		
    try {
      prop.store(new FileOutputStream("test.properties"),"My Favorite Song");
    } catch (IOException e) {
      System.out.println(e.getMessage());
    }
  }
}
PropertiesLoad.java
package net.java_school.collection;

import java.util.*;
import java.io.*;

public class PropertiesLoad {
  public static void main(String[] args) {
	
    Properties prop = new Properties();
    try {
      prop.load(new FileInputStream("test.properties"));
    } catch (IOException e) {
      System.out.println(e.getMessage());
    }
    System.out.println(prop.getProperty("title"));
    System.out.println(prop.getProperty("singer"));
  }
}
C:\ Command Prompt
C:\java\Collection\bin>java net.java_school.collection.PropertiesStore

C:\java\Collection\bin>java net.java_school.collection.PropertiesLoad
Back in Black
AC/DC

Running the PropertiesStore will create a test.properties file on the file system.

The file's location is different when you run it in Eclipse or when you run it from the command prompt. Eclipse creates the file in the project directory. If you think it is ambiguous, you can pass the full path of the file system to the constructor of FileOutputStream and FileInputStream in the above code as follows.

new FileOutputStream("C:/java/Collection/test.properties"), new FileInputStream("C:/java/Collection/test.properties")

The file contents are as follows:

test.properties
#My Favorite Song
#Thu Apr 10 13:07:41 KST 2014
singer=AC/DC
title=Back in Black

Enumeration

It is an interface with the necessary methods for retrieving objects stored in enumerated form from beginning to end.
It has two methods:

  • hasMoreElements()
  • nextElement()

Vector implements the Enumeration interface.
The following code outputs all elements of the Vector.

for (Enumeration<E> e = v.elements(); e.hasMoreElements();) {
  System.out.println(e.nextElement());
}

Let's modify the previous Vector example to use Enumeration.
Performance is lower than in the previous example.

VectorExample.java Using Generic, Enumeration
package net.java_school.collection;

import java.util.*;

public class VectorExample {
  public static void main(String[] args) {
	
    Vector<String> v = new Vector<String>();
	
    for (int i = 0; i < 10; i++) {
      v.addElement(String.valueOf(Math.random() * 100));
    }
		
    for (Enumeration<String> e = v.elements(); e.hasMoreElements();) {
      System.out.println(e.nextElement());
    }
  }
}

Iterator

Iterator is similar to the Enumeration interface, created later than the Enumeration. Method names are simpler than Enumeration. Unlike Enumeration, Iterator has a method to delete values.

The Collection interface has the iterator() method. Every class that implements the Set or List interface must have an iterator() method because the Set and List interfaces inherit the Collection interface.

The iterator() method returns the Iterator interface type. Of course, because the Iterator is an interface, the actual return is an object created from the implementation class that implements Iterator. But we do not have to worry about what the implementation class is. It is sufficient that the implementation class implements the Iterator interface.

  • hasNext()
  • next()
  • remove()

Wrapper

Unlike arrays, Collection can contain only reference values. You can not store a primitive data type value in Collection. The answer is to use the wrapper class to store primitive type values in Collection. There are corresponding wrapper classes for all primitive types. A wrapper instance consists of a primitive data type value and methods that manipulate that value.

Primitive Data Type Wrapper Class
boolean Boolean
byte Byte
char Character
short Short
int Integer
long Long
float Float
double Double
IntegerExample.java
package net.java_school.collection;

public class IntegerExample {

  public static void main(String[] args) {
    Integer a = new Integer(2000000000);
    int intValue = a.intValue();
    System.out.println(intValue);

    byte byteValue = a.byteValue();
    System.out.println(byteValue);
		
    short shortValue = a.shortValue();
    System.out.println(shortValue);
		
    long longValue = a.longValue();
    System.out.println(longValue);
		
    float floatValue = a.floatValue();
    System.out.println(floatValue);
		
    double doubleValue = a.doubleValue();
    System.out.println(doubleValue);
		
    String strValue = a.toString();
    System.out.println(strValue);

    System.out.println(Integer.MAX_VALUE);
    System.out.println(Integer.MIN_VALUE);
    System.out.println(Integer.parseInt("1004"));

    /* 
    * The following code is changed by the compiler to Integer b = new Integer(200000000); 
    * This is called AutoBoxing.
    * AutoBoxing is not a casting.
    * There is no casting that converts a primitive datatype to a reference datatype.		  
    */
    Integer b = 2000000000;
	
    /* 
     * == always asks if the values are the same. 
     * If it is a reference value, it is judged whether it is the same object or not.
    */
    if (a == b) {
      System.out.println("a == b true");
    } else {
      System.out.println("a == b false");
    }
		
    /* 
     * To determine if a and b have the same int value, use the equals() method of Integer.
     * The equals() method of Integer overrides Object's equals method to determine if int values are equal.
     if (obj instanceof Integer) {
       return value == ((Integer)obj).intValue();
     }
     return false;  
    */
    if (a.equals(b)) {
      System.out.println("a.equals(b) true");
    } else {
      System.out.println("a.equals(b) false");
    }
		
    /*
     * Use the compareTo() method of Integer to determine the values of a and b in various ways. 
    */
    int check = a.compareTo(b);
    System.out.println(check);
    if (check == 0) {
      System.out.println("a(int) == b(int)");
    } else if (check < 0) {
      System.out.println("a(int) < b(int)");
    } else {
      System.out.println("a(int) > b(int)");
    }
		
    int c = 2000000000;
    if (a.equals(c)) { // The compiler changes c to a reference to new Integer(c).
      System.out.println("a.equals(c) true");
    } else {
      System.out.println("a.equals(c) false");
    }
		
    /*
     * It appears that a copy of the int value in the Integer object 
     * referenced by a is assigned to the variable d of the primitive type outside the object.
     * This is called AutoUnboxing.
    */
    int d = a; //The compiler changes this code to int d = a.intValue();
    System.out.println(d);
		
    /*
    * obj is assigned a reference to an Integer object containing a 1.
    * The fact is that the compiler modifies this code to Object obj = new Integer(1);
    */
    Object obj = 1;
    System.out.println(obj);
		
    /*
    * You can not call an Integer's original method using a reference of type Object.
    * Casting is necessary.
    System.out.println(((Integer)obj).intValue());
  }
}

C:\ Command Prompt
C:\java\Collection\bin>java net.java_school.collection.IntegerExample
2000000000
0
-27648
2000000000
2.0E9
2.0E9
2000000000
2147483647
-2147483648
1004
a == b false
a.equals(b) true
0
a(int) == b(int)
a.equals(c) true
2000000000
1
1

Java provides AutoBoxing and Auto Unboxing for ease of development. You may have seen a magic trick: Inserting and withdrawing coins in a glass box without a lid. AutoBoxing puts a coin in a box, and Auto Unboxing takes a coin out of a box.

References