Learn Java Programming
3.0 Collections
Collections
The following are the objectives of this lesson. End of this lesson, you should be able to understand the following:
- Why do we need collections
- What is an array – some drawbacks of the array (like we need to know the type in advance and we need to know the size in advance)
- Why do we need a List – features of the list
- Accessing elements of the list – When to use a For-Loop and when to use an iterator
- Different List implementations in Java
- How do we avoid duplicate elements in a collection of objects
- How to sort elements in a List – using the Comparator interface
- How to organize objects – Why do we need a map
- How to organize objects based on some key identifier – What is a KEY?
- How to access elements based on the key
- How to get the different keys from a Map
- General coding principles – declaring variables as only INTERFACE type and NOT CONCRETE Type
Often in our programs we deal with more than one object. We for the most would be programming with more than one object. Java gives us a mechanism to group objects together, using the Collections framework.
(API stands for Application Programmer Interface – and is the set of classes that Java provides to us programmers as part of the Java Development Kit JDK)
Let us begin with Arrays:
Arrays
The first collection we would encounter is an Array. Array is a collection on “similar” objects. By similar we mean, a group of objects belonging to the same Class. We would say, A Collection is a group of objects that have the same type. To declare an array, we need to define the number of elements in the array. For example:
Student[] students = new Student[5];
Here students refers to an array of students, whose array size is 5. To add objects to an array, we use the following syntax:
students[0] = s1;
students[1] = s2;
students[2] = s3;
students[3] = s4;
students[4] = s5;
Array objects are indexed using an integer value. If an array is declared of size 5, then the indexes would start from 0 up-to size-1. That is, the allowed indexes would be from 0,1,2,3 and 4
To access the objects from the array, again, we would use the index.
Student s1 = students[0];
Student s2 = students[1];
Student s3 = students[2];
Student s4 = students[3];
Student s5 = students[4];
To access student objects objects, we could use the for-loop with index or the new style for-loop
To get the size of the array, we use the method students.length.
Note since the array index is [array length – 1] one less than the total size of the array, our for-loop will continue till the condition i is less than students.length:
for (int i=0; i < students.length; i++) {
Student s = students[i];
System.out.println(s);
}
for (Student s: students) {
System.out.println(s);
}
Filename: ArrayDemo.java
public class ArrayDemo {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("Jack"); s1.setAge(18);
s1.setAdmissionNumber(123);
Student s2 = new Student();
s2.setName("Jill"); s2.setAge(18);
s2.setAdmissionNumber(456);
Student s3 = new Student();
s3.setName("Humpty Dumpty"); s3.setAge(14);
s3.setAdmissionNumber(789);
Student s4 = new Student();
s4.setName("Mary"); s4.setAge(15);
s4.setAdmissionNumber(987);
Student s5 = new Student();
s5.setName("Johnny"); s5.setAge(10);
s5.setAdmissionNumber(654);
Student[] students = new Student[5];
students[0] = s1;
students[1] = s2;
students[2] = s3;
students[3] = s4;
students[4] = s5;
System.out.println("---Accessing using for-loop with index ---");
for (int i=0; i < students.length; i++) {
Student s = students[i];
System.out.println(s);
}
System.out.println();
System.out.println("Accessing using new style for-loop");
System.out.println();
for (Student s: students) {
System.out.println(s);
}
}
}
Drawback of Arrays:
One of the major drawbacks of arrays is that we need to know the size of the array in advance. It is very rarely in our programs that we know the size of the group of objects in advance.
If we know that the collection is going to be of fixed size and of same type of objects, then using an Array is the best choice.
Lists
Java provides a List object to represent a group of objects. List allows us to add objects, retrieve them and even remove them from the list. Please note that a List is defined as an interface type in Java. Some of the implementations of List are ArrayList, LinkedList, Stack and Vector.
We declare a List variable as follows:
List studentList = new ArrayList();
You could declare a studentList using the following syntax,
ArrayList studentList = new ArrayList();
but this is not recommended!
From JDK 1.5 onwards, we are encouraged to declare a List with the type of elements in the List
List<Studentt> studentList = new ArrayList<Studentt>();
Here studentList can contain only elements of type Student, and is called a Type Safe List
List<Studentt> studentList = new ArrayList<Studentt>();
studentList.add(s1);
studentList.add(s2);
studentList.add(s3);
studentList.add(s4);
studentList.add(s5);
studentList.add(s3);
Note: List allows us to add duplicate elements!
Methods on the List
A List has several methods that lets us know the size of the List, to retrieve the contents, add elements to a list or even check if a list is empty:
To add elements to the list
studentList.add(student4);
To get the size of the list
int listCount = studentList.size();
To retrieve an element from the list. We need to specify the index
Student student = (Student) studentList.get(2);
This will get the third element from the list (since the index starts from 0)
To check whether a list is empty or not
boolean empty = studentList.isEmpty();
Returns true if the list is empty.
Accessing elements in the list
A List is built for sequential access. Since a List can grow dynamically in size as opposed to an array that has a fixed size.
The elements in a List can be accessed in two ways :
1.Using a for-loop
2.Using an Iterator
1. Using the for-loop
int noOfStudents = studentList.size();
for (int i = 0; i < noOfStudents; i++) {
Student student = (Student) studentList.get(i);
System.out.println(student);
}
2. Using the Iterator interface
Using the iterator interface to loop through the elements in the List, is similar to that of the for-loop. But iterator has methods to manipulate the contents of the List using a remove() method.
Iterator iter = studentList.iterator();
while (iter.hasNext()) {
Student student = (Student) iter.next();
System.out.println(student);
}
First get the iterator for the List using the iterator() method on the List interface.
Then use the iter variable to loop through the elements, using the next() method. Continue this as long as the hasNext() method returns a boolean true value.
Filename: ListDemo.java
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
public class ListDemo {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("Jack");
s1.setAge(18);
s1.setAdmissionNumber(123);
Student s2 = new Student();
s2.setName("Jill");
s2.setAge(18);
s2.setAdmissionNumber(456);
Student s3 = new Student();
s3.setName("Humpty Dumpty");
s3.setAge(14);
s3.setAdmissionNumber(789);
Student s4 = new Student();
s4.setName("Mary");
s4.setAge(15);
s4.setAdmissionNumber(987);
Student s5 = new Student();
s5.setName("Johnny");
s5.setAge(10);
s5.setAdmissionNumber(654);
List<Student> studentList = new ArrayList<Student>();
studentList.add(s1);
studentList.add(s2);
studentList.add(s3);
studentList.add(s4);
studentList.add(s5);
studentList.add(s2);
studentList.add(s3);
studentList.add(s4);
System.out.println("---Accessing using for-loop with index ---");
for (int i=0; i < studentList.size(); i++) {
Student s = studentList.get(i);
System.out.println(s);
}
System.out.println();
System.out.println("---Accessing using the iterator ---");
System.out.println();
Iterator iter = studentList.iterator();
while (iter.hasNext()) {
Student student = (Student) iter.next();
System.out.println(student);
}
}
}
Set
Using the Set interface is similar to the List. But the important distinction here is that the Set interface does not support duplicates
Set is defined as a interface in Java, and has the following implementations – HashSet, EnumSet
To declare a Set variable we use something like the following:
Set<Student> studentSet = new HashSet<Student>();
How does Java weed out the duplicates while adding elements to a Set.
Remember the hashcode() method we implemented in the previous session. We know the rule, that when two objects are the same, then their hashcode should also be equal. Java uses the hashcode to check for duplicates.
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
public class SetDemo {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("Jack");
s1.setAge(18);
s1.setAdmissionNumber(123);
Student s2 = new Student();
s2.setName("Jill");
s2.setAge(18);
s2.setAdmissionNumber(456);
Student s3 = new Student();
s3.setName("Humpty Dumpty");
s3.setAge(14);
s3.setAdmissionNumber(789);
Student s4 = new Student();
s4.setName("Mary");
s4.setAge(15);
s4.setAdmissionNumber(987);
Student s5 = new Student();
s5.setName("Johnny");
s5.setAge(10);
s5.setAdmissionNumber(654);
Set<Student> studentSet = new HashSet<Student>();
System.out.println("Adding " + s1 );
studentSet.add(s1);
System.out.println("Adding " + s2 );
studentSet.add(s2);
System.out.println("Adding " + s3 );
studentSet.add(s3);
System.out.println("Adding " + s4 );
studentSet.add(s4);
System.out.println("Adding " + s5 );
studentSet.add(s5);
System.out.println("Again adding " + s2 );
studentSet.add(s2);
System.out.println("Again adding " + s3 );
studentSet.add(s3);
System.out.println("Again adding " + s4 );
studentSet.add(s4);
System.out.println();
System.out.println("---Accessing using the Set elements ---");
System.out.println();
Iterator iter = studentSet.iterator();
while (iter.hasNext()) {
Student student = (Student) iter.next();
System.out.println(student);
}
}
}
Note, the contents of the Set will not be ordered in the way we added them – if you want to keep the ordering, then you must use the TreeSet implementation.
We will wait on the TreeSet implementation till we discuss Sorting elements.
Sorting a collection
Java gives us an easy way out to sort a collection. Only we need to tell Java, what is the criteria for sorting. All we need to do is to write a Java class that implements the Comparable interface, and pass it to the sorting algorithms.
The sorting algorithm, then sorts the data in the list according to the criteria specified in the Comparable implementation.
Lets say, we want to sort the student collection based on the name
Filename: StudentComparator.java
import java.util.Comparator;
public class StudentComparator implements Comparator {
public int compare(Object obj1, Object obj2) {
Student s1 = (Student) obj1;
Student s2 = (Student) obj2;
return s1.getName().compareTo(s2.getName());
}
}
To sort the list, all we need to do is to instantiate the comparator, and pass it to the Collections.sort() method:
Comparator mycomp= new StudentComparator();
Collections.sort(studentList, mycomp);
System.out.println("Printing sorted list...");
for (int i = 0; i < noOfStudents; i++) {
Student studentFromList = (Student) studentList.get(i);
System.out.println(studentFromList);
}
Preserving the original order in a Collection
Let us say you want to preserve the original order of adding elements to the Set. Then use a TreeSet
Set<Student> studentSet = new TreeSet<Student>( new StudentComparator());
While creating the TreeSet object, we need to pass in the Comparator that would be used for Comparisons.
File name: TreeSetDemo.java
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("Jack");
s1.setAge(18);
s1.setAdmissionNumber(123);
Student s2 = new Student();
s2.setName("Jill");
s2.setAge(18);
s2.setAdmissionNumber(456);
Student s3 = new Student();
s3.setName("Humpty Dumpty");
s3.setAge(14);
s3.setAdmissionNumber(789);
Student s4 = new Student();
s4.setName("Mary");
s4.setAge(15);
s4.setAdmissionNumber(987);
Student s5 = new Student();
s5.setName("Johnny");
s5.setAge(10);
s5.setAdmissionNumber(654);
Set<Student> studentSet = new TreeSet<Student>( new StudentComparator());
System.out.println("Adding " + s1 );
studentSet.add(s1);
System.out.println("Adding " + s2 );
studentSet.add(s2);
System.out.println("Adding " + s3 );
studentSet.add(s3);
System.out.println("Adding " + s4 );
studentSet.add(s4);
System.out.println("Adding " + s5 );
studentSet.add(s5);
System.out.println("Again adding " + s2 );
studentSet.add(s2);
System.out.println("Again adding " + s3 );
studentSet.add(s3);
System.out.println("Again adding " + s4 );
studentSet.add(s4);
System.out.println();
System.out.println("---Accessing using the Set elements ---");
System.out.println();
Iterator iter = studentSet.iterator();
while (iter.hasNext()) {
Student student = (Student) iter.next();
System.out.println(student);
}
}
}
Maps
Java gives us a convenient ways to organize data into groups.
Lets say we have a group of students and we want to group them by their course. Let us say we have 3 category of students, based on their course [ Computer Science, Medicine and Management Studies]
And let us say for example, we want all the Computer Science students grouped together, the Management Studies students grouped together and the Medical students into a separate group.
The Java language gives us a convenient way of organizing objects based on the key – value pairs.
The Map interface consists of a set of keys, and values corresponding to the keys.
If using the above example, we were to organize the students data, based on their course:
The keys would be the different value of the courses, and the values would be the list of students for these courses.
Map courseMap = new HashMap();
for (int i=0; i < noOfStudents; i++) {
//-- First get the student
Student stud = (Student) studentList.get(i);
//-- Then get the course that the student belongs to
String course = stud.getCourse();
if (studentMap.containsKey(course)) {
//-- Check if the map already contains a key for this course.
//-- If a key exists, then the value for the key must be a List
//-- Get that list and add the Student object [stud] to the list
//-- and we are done
System.out.println("Student from [" + course + "] exists - adding");
List<Student> studList = (List) studentMap.get(course);
studList.add(stud);
studentMap.put(course, studList);
} else {
//-- The key does not exist for this course
//-- Create a new key and a List
//-- Add the Student object [stud] to the list
//-- Add the key and value to the Map
System.out.println("Adding a new course [" + course + "]");
List<Student> studList = new ArrayList<Student>();
studList.add(stud);
studentMap.put(course, studList);
}
}
Getting data from a Map:
If we need to access only students undergoing Management Studies, here is how we do that:
List studList = (List) studentMap.get("Management Studies");
for (int i=0; i < studList.size(); i++) {
System.out.println((Student) studList.get(i));
}
Getting the Keys from a Map:
It is possible to get only the keys from the Map. In the example below we get all the keys (distinct courses) from the Map.
System.out.println("Now fetching all the distinct courses");
Set courses = courseMap.keySet();
Iterator iter = courses.iterator();
while (iter.hasNext()) {
String course= (String) iter.next();
System.out.println(course);
}
Here is the complete code listing for reference:
Filename: MapDemo.java
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
public class MapDemo {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("Jack");
s1.setAge(18);
s1.setAdmissionNumber(123);
Student s2 = new Student();
s2.setName("Jill");
s2.setAge(18);
s2.setAdmissionNumber(456);
Student s3 = new Student();
s3.setName("Humpty Dumpty");
s3.setAge(14);
s3.setAdmissionNumber(789);
Student s4 = new Student();
s4.setName("Mary");
s4.setAge(15);
s4.setAdmissionNumber(987);
Student s5 = new Student();
s5.setName("Johnny");
s5.setAge(10);
s5.setAdmissionNumber(654);
List<Studentt> studentList = new ArrayList<Studentt>();
studentList.add(s1);
studentList.add(s2);
studentList.add(s3);
studentList.add(s4);
studentList.add(s5);
Map<String, List<Student>> courseMap
= new HashMap<String, List<Student>>();
for (int i=0; i < studentList.size(); i++) {
//-- First get the student
Student stud = (Student) studentList.get(i);
//-- Then get the course that the student belongs to
String course = stud.getCourse();
if (courseMap.containsKey(course)) {
//-- Check if the map already contains a key for this course.
//-- If a key exists, then the value for the key must be a List
//-- Get that list and add the Student object [stud] to the list
//-- and we are done
System.out.println("Student from [" + course
+ "] exists - adding to existing List of students");
List<Student>> studList = (List) courseMap.get(course);
studList.add(stud);
courseMap.put(course, studList);
} else {
//-- The key does not exist for this course
//-- Create a new key and a List
//-- Add the Student object [stud] to the list
//-- Add the key and value to the Map
System.out.println("Adding a new course [" + course
+ "] - Creating a list for these students");
List<Student> studList = new ArrayList<Student>();
studList.add(stud);
courseMap.put(course, studList);
}
}
System.out.println("---Getting Computer Science Students ---");
List studList = (List) courseMap.get("Computer Science");
for (int i=0; i < studList.size(); i++) {
System.out.println((Student) studList.get(i));
}
System.out.println("---Getting Management Students ---");
List studManagementStudiesList
= (List) courseMap.get("Management Studies");
for (int i=0; i < studManagementStudiesList.size(); i++) {
System.out.println((Student) studManagementStudiesList.get(i));
}
System.out.println("---Getting Medical Students ---");
List studMedicineList = (List) courseMap.get("Medicine");
for (int i=0; i < studMedicineList.size(); i++) {
System.out.println((Student) studMedicineList.get(i));
}
System.out.println("---Getting Distinct Courses ---");
Set courses = courseMap.keySet();
Iterator iter = courses.iterator();
while (iter.hasNext()) {
String course= (String) iter.next();
System.out.println(course);
}
}
}
Summary:
Here we took an in depth look at the Java Collections and have learned the following:
- Understand the Array in Java – and its limitations. We saw how to define an array, add elements to it and access the array elements
- Understand the List interface – how to add elements to the list, and iterate over the list
- How to eliminate duplicates from a list
- How to Sort a List
- How to preserve the order of Sorting
- Organizing objects into groups based on Key-Value pairs