Lecture # 16: Java Collections API
SE 241 Advance Computer Programming
Muhammad Imran adopted from Dr. Usman Nasir
What is a Collection?
An object that contains other objects or
groups multiple elements into a single unit.
Used to store, retrieve and manipulate data.
It can consist of any types of objects
Java Collection API
Java Collections API provide a set of
classes and interfaces that makes it
easier to work with collections of objects
Provides a basic set of Object Containers.
Core data structures for everyday coding.
Unified architecture for representing and
manipulating collections.
It has Interfaces and Implementations
There are two groups of standard
interfaces in Java Collections API:
Collections
Map
Collection Map
(interface) (interface)
List Set HashMap
** Partial map of API
classes
Generics in Collections
A non-generic collection can store any type
of object (Any type)
This helps in mixing object in collection but
then it is up to programmer to check and
type-cast it every time.
Generics force the java programmer to
store a specific type of objects in a
collection.
This way is efficient and reduces errors
diamond operator <>are used to define
generics
Collections to Array
Collection object can be used with Object
Arrays
Collection c = new ArrayList();
c.add(19);
c.add("hello");
Object[] array = c.toArray();
Collection Interface
java.util.Collection
Collection Interface
Java Collection interface
(java.util.Collection) is one of the root
interfaces of the Java Collection API.
You can not instantiate a Collection
directly, but its sub types are implemented
Collection collection = new ArrayList();
Available collection types that extends the
Java Collection interface:
List, Set, SortedSet, NavigableSet, Queue,
Deque
Some methods of Collection
Interface
boolean add(Object o)
Ensures that this collection contains the specified
element.
void clear()
Removes all of the elements from this collection
boolean contains(Object o)
Returns true if this collection contains the specified
element.
boolean equals(Object o)
Compares the specified object with this collection for
equality.
boolean isEmpty()
Returns true if this collection contains no elements.
Iterator iterator()
Returns an iterator over the elements in this
collection.
boolean remove(Object o)
Removes a single instance of the specified element
from this collection, if it is present
int size()
Returns the number of elements in this collection.
Object[] toArray()
Returns an array containing all of the elements in this
collection
Java List
java.util.List is an interface that represents
an ordered sequence of objects.
Each element in a Java List has an index
starting from 0.
Any Java object can be added to a List.
Available implementations of List
java.util.ArrayList
java.util.LinkedList
java.util.Vector //deprecated
java.util.Stack
ArrayList
ArrayList implements List interface
The ArrayList will automatically increase to
accommodate elements.
ArrayList operations are slightly slower
than array operations.
Use
import java.util.ArrayList;
Declaration
List myList = new ArrayList();
// Adding elements
myList.add("Malik");
myList.add(30);
myList.add(11.25);
//Compile Error:incompatible types: java.lang.Object
//cannot be converted
String name = myList.get(0);
int age= myList.get(1);
double score= myList.get(2);
Declaration
List myList = new ArrayList();
// Adding elements
myList.add("Malik");
myList.add(30);
myList.add(11.25);
//Explicit casting is required for each element
String name = (String) myList.get(0);
int age= (int) myList.get(1);
double score= (double) myList.get(2);
After using generics we do not need to type
cast as entire collection type casted to given
type.
List<String> listGen = new ArrayList<String>();
listGen.add("hello");
String ss = listGen.get(0);
listGen.add(50);//this will give error now
Why??
Another style of declaration:
List<String> listGen = new ArrayList<>();
import java.util.* ;
public class ArrayListExample{
public static void main ( String[ ] args) {
// Create an ArrayList that holds references to String
List<String> names = new ArrayList<String>();
// Add three String references
names.add("Malik"); names.add("Bashir");
names.add("Zameer");
// Access and print out the three String Objects
System.out.println(“Element 0: " + names.get(0) );
System.out.println(”Element 1: " + names.get(1) );
System.out.println(”Element 2: " + names.get(2) );
Element 0: Malik
}
Element 1: Bashir
} Element 2: Zameer
public class Customer{
public Customer(int aId, String aName){ customerId=aId;
customerName=aName; }
public String toString() { return "Customer: id: "+customerId+"
"+customerName; }
private int customerId; private String customerName;}
_____________________________________________________
______
import java.util.*;
public class Example2{
public static void main ( String[ ] args) {
ArrayList <Customer> listCustomer = new
ArrayList<Customer>(); Example2
listCustomer.add(new Customer(1,"Ali")); Customer: id: 2
Customer cust2=new Customer(2,"Sameer"); Sameer
listCustomer.add(1,cust2);
Linked List
LinkedList is implemented as a double linked
list.
List<String> list = new LinkedList<>();
list.add("hello");
list.add("hi");
list.add("bye");
System.out.println("Element 0: " + list.get(0) );
System.out.println("Element 1: " + list.get(1) );
System.out.println("Element 2: " + list.get(2) );
ArrayList versus LinkedList
ArrayList LinkedList
An array that Classic doubly
linked list.
resizes when it
Constant time for
gets full. insertion and
Insertion to the removal anywhere
front or middle is in the list.
expensive. Slower iteration.
get(int) very slow
Provides fast
(implemented by
iterator and get(int) iterating).
methods.
Set Interface
Set interface extends Collection interface.
In a set, no duplicates are allowed.
Every element in a set must be unique. You
can simply add elements to a set, and
duplicates will be removed automatically.
Some of the implementing classes are:
java.util.HashSet
java.util.EnumSet
java.util.LinkedHashSet
java.util.TreeSet
HashSet class
Creates a collections and uses a hash
table for storage
Uses hashing
Execution time of basic operations is
constant
No order maintained
Example: HashSet
import java.util.*;
public class FindDups {
public static void main(String args[]) {
Set<String> myset = new HashSet<String>();
for (int i=0; i < args.length; i++) {
if (! myset.add(args[i]) )
System.out.println("Duplicate detected: "
+args[i]);}
System.out.println(myset.size() + " distinct
words detected: " + myset); } }
Running the Example
$ java FindDups i came i saw i left
Duplicate word detected: i
Duplicate word detected: i
4 distinct words detected: [came, i, left, saw]
Set vs List
Set List
Faithful to the Sequential
mathematical structures.
definition. Duplicates
No methods added allowed.
to Collection Implements get
(simply enforces and remove
“no duplicates” methods using
rule using the integer index.
equals method).
Queue
java.util.Queue interface represents queue
data structure.
It is designed to have elements inserted at the
end of the queue and removed from the top.
Queue interface is a subtype of the Java
Collection interface
Java Queue Implementations
java.util.LinkedList
java.util.PriorityQueue
//import java.util.Queue;
// Queue using a LinkedList
Queue<String> waitingQueue = new LinkedList<>();
// Adding elements to the Queue
waitingQueue.add("Abdul");
waitingQueue.add("Bashir");
waitingQueue.add("Karim");
System.out.println("WaitingQueue : " + waitingQueue);
// Removing an element (Dequeue operation)
String name = waitingQueue.remove();
System.out.println("Removed from queue : " + name);
System.out.println("New queue: " + waitingQueue);
Output:
WaitingQueue : [Abdul, Bashir,
Karim]
Removed from queue : Abdul
Map Interface
java.util.Map
Map Interface
java.util.Map represents a mapping
between a key and a value.
Maps stores associations between keys
and values
Key/values both are objects and keys are
unique
Not collections, but provide a collections
view
Java Collections API contains the following
Map implementations:
java.util.HashMap
java.util.Hashtable
java.util.EnumMap
java.util.IdentityHashMap
java.util.LinkedHashMap
java.util.Properties (must study on your own)
java.util.TreeMap
java.util.WeakHashMap
Map Interface - Methods
Object put(Object key, Object value)
Associates the specified value with the
specified key in this map
//adds
Object get(Object key)
Returns the value to which this map maps the
specified key.
//get
boolean isEmpty()
Returns true if this map contains no key-value
mappings.
HashMap Example
public static void main(String[] args) {
HashMap<Integer, String> map = new
HashMap<Integer, String>();
map.put(10, "Ali"); map.put(12, "Jamal");
map.put(12, "Asad"); //What happens to
duplicate keys
map.put(14, "Samad");
System.out.println("Size of map is:- " +
map.size());
System.out.println(map);
System.out.println("The value for key is :" +
map.get(10));
Output:
Size of map is: 3
{10=Ali, 12=Asad, 14=Samad}
The value for key is : Ali
{}
Hashtable (depreciated now)
Hashtable<String, MyStudent> hashTbl = new
Hashtable<>();
hashTbl.put ("1", new MyStudent("1","Ali");
hashTbl.put ("2", new
MyStudent("2","Saleem"));
hashTbl.put ("3", new MyStudent("z","Zafar"));
//hashTbl.put (null, new
MyStudent("z","Zafar"));
//hashTbl.put("4", null);
System.out.println (hashTbl);
{3=z,Zafar, 2=2,Saleem, 1=1,Ali}
HashMap vs HashTable
Hashtable<Integer,String> ht=new
Hashtable<>();
ht.put(101,"Samad"); ht.put(101,"Ali");
ht.put(102,"Khalid"); ht.put(103,"Ali");
System.out.println("--------Hash table---------");
System.out.println(ht);
HashMap<Integer,String> hm=new
HashMap<>();
hm.put(101,"Samad"); hm.put(101,"Ali");
hm.put(null,null); hm.put(103,"Ali");
System.out.println("-------Hash map----------");
System.out.println(hm);
Output
-------------Hash table--------------
{103=Ali, 102=Khalid, 101=Ali}
-----------Hash map-----------
{null=null, 101=Ali, 103=Ali}
Hashmap vs Hashtable
HashMap is non synchronized thus not-
thread safe
HashMap allows one null key and multiple
null values whereas Hashtable doesn’t
allow any null key or value.
HashMap is generally preferred over
HashTable if thread synchronization is not
needed
equals() and hashCode()
Java hashCode() and equals()
In Collection both hashCode() and equals()
methods are used to compare objects in
collections.
equals( ) is used in most collections to
determine if a collection contains a given
element.
List list = new ArrayList();
list.add("123");
boolean contains123 = list.contains("123");
//contains will be calling equals of each element with
"123" and compare string
Shallow comparison:
The default implementation of equals method is
defined in Java.lang.Object class which simply
checks if two Object references refer to the same
Object.
Deep Comparison:
That means data members of Objects are to be
compared with one another.
For user defined Object equals() must be
overloaded, as it depends on your application
that when two objects are equal.
public class Employee {
private long employeeId;
private String name;
public Employee(long employeeId, String aName) {
this.employeeId = employeeId;
this.name = aName;
}
public static void main(String[] args) {
Employee one = new Employee(0100, "Ali");
Employee two = new Employee(0100, "Ali");
System.out.println(one.equals(two));
} Output: false
}//
public class Employee {
//overriding equals Employee equals if id is same
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof Employee)) return false;
Employee other = (Employee) o;
return this.employeeId == other.employeeId;
}
public static void main(String[] args) {
Employee one = new Employee(0100, "Ali");
Employee two = new Employee(0100, "Ali");
System.out.println( one.equals(two) );
} Output: true
}//
Overriding of equals depends on
implementation:
It can be comparing id only if you have to
lookup an Employee object from a cache.
It can be comparing every field if you have to
check that if a copy of an Employee object has
changed from the original.
hashCode( )
This method is provided by java.lang.Object and
returns an integer representation of the object
memory address.
Used when inserting/comparing/removing objects
into HashTable, HashMap or HashSet.
By default, this method returns a random integer
that is unique for each instance
You should override if you need it but best is
to follow this
If object1 and object2 are equal according to their
equals() method, they must also have the same
hash code.
If object1 and object2 have the same hash code,
they do not have to be equal too.
public class Employee {
private long employeeId; private String name;
@Override
public int hashCode(){
return (int) employeeId;
}
public static void main(String[] args) {
Employee one = new Employee(0100, "Ali");
Employee two = new Employee(0100, "Ali");
System.out.println(one.equals(two));
}
Output: true
}//
Some guidelines
As a rule, when you override equals() you
must also override hashcode()
You should only execute an equals() method
for objects that have the same hashcode.
You should not execute equals() when the
hashcode is different.
When a hashcode() comparison returns false,
the equals() method must also return false and
vice versa.
Iterator and Iterable
Iterator
Iterator interface gives a standardized way
for iterating elements within a collection.
All collections implements the iterator
Allows elements of any collection to be
accessed through iterators
Replaces
int counter;
int size = collection.size();
for (counter=0; counter < size; counter++){
Object value = collection.get(counter);
}
With
Iterator i = collection.iterator();
while(i.hasNext()) {
Object value = i.next();
}
Using Iterator
ArrayList<String> names = new ArrayList<>();
names.add("Sameer");
names.add("Waleed");
names.add("Sami");
Iterator it = names.iterator();
while ( it.hasNext() ){
String obj = (String)it.next();
System.out.println(obj);
}
Some collections do not allow modification
of the collection while using Iterator.
Throws ConcurrentModificationException on
add( ) but not on remove( )
Iterable
A class that implements the Java Iterable
(java.lang.Iterable) interface can be
iterated with the Java for-each loop.
Several classes in Java that implements
the Java Iterable interface.
The Collection interface extends Iterable,
so all subtypes of Collection also
implement the Iterable interface.
Java List and Set interfaces etc.
//ArrayList is Iterable
List list = new ArrayList();
list.add("one");
list.add("two");
list.add("three");
for(Object o : list){
System.out.println(o.toString());
}
Java.util.Iterable Interface has only method
public Iterator <T> iterator( )
public interface Iterable<T> {
public Iterator<T> iterator();
}
To make your own classes Iterable
requires implementing Iterable interface.
public class Persons implements Iterable {
private List<Person> persons = new
ArrayList<Person>();
public Iterator<Person> iterator() {
return this.persons.iterator( );
}
}
Persons persons = new Persons();//assuming some
elements are in List
for(Person person : persons) {
// do something with person object.
}
Comparator and Comparable
Comparable
Comparable is an interface that helps in defining a
strategy of comparing an object with other objects
of the same type.
Class's “natural ordering”.
Collections.sort( ) use object that have
implemented Comparable interface.
public interface Comparable {
/* a negative integer, zero, or a positive integer as this object
is less than, equal to, or greater than the specified object.*/
public int compareTo(Object o);
}
Example
Lets take a class Player. Players are
compared with each other based on their
ranking
public class Player {
private int ranking;
private String name;
private int age;
// constructor, getters, setters
}
List<Player> hockeyteam = new ArrayList<>();
hockeyteam.add(new Player(12, "Zaeem",32));
hockeyteam.add(new Player(18, "Samad",29));
hockeyteam.add(new Player(07, "Abdul",21));
System.out.println("Before Team : " +
hockeyteam);
Collections.sort(hockeyteam);//will not work
System.out.println("After Team : " +
hockeyteam);
//How does Java know how to compare Player A with
B?
public class Player implements
Comparable<Player>
{
//other methods and code remain
@Override
public int compareTo(Player otherPlayer) {
return (this.getRanking() -
otherPlayer.getRanking());
}
}
List<Player> hockeyteam = new ArrayList<>();
hockeyteam.add(new Player(12, "Zaeem",32));
hockeyteam.add(new Player(18, "Samad",29));
hockeyteam.add(new Player(07, "Abdul",21));
System.out.println("Before Team : " +
hockeyteam);
Collections.sort(hockeyteam);//will now
work
System.out.println("After Team : " +
Output:
hockeyteam);
Before Team : [Player{12, 'Zaeem', 32}, Player{7, 'Abdul', 21}, Player{18,
'Samad', 29}]
After Team : [Player{7, 'Abdul', 21}, Player{12, 'Zaeem', 32}, Player{18,
'Samad', 29}]
Comparator
At time programmer needs to have multiple
logics to do comparisons of objects. This
become an issue as in compareTo method
you can have one logic.
Using a class that implements the
Comparator interface can become as basis of
comparison logic.
The user defined class does not need to
implement Comparable interface now with
this approach but that can be left as default
approach.
Use javadoc to share info about comparison logic
Comparator Interface
Comparator interface defines a compare
method with two arguments which
compares objects.
Only only method:
public int compare(Obj one, Object two)
/*a negative integer, zero, or a positive integer as
the
* first argument is less than, equal to, or greater
than * the second.*/
import java.util.Comparator;
public class PlayerNameComparator implements
Comparator<Player> {
@Override
public int compare(Player firstPlayer, Player
secondPlayer) {
return
firstPlayer.getName().compareTo(secondPlayer.getN
ame());
}
}
//Age is used to compare
public class PlayerAgeComparator implements
Comparator<Player> {
@Override
public int compare(Player firstPlayer, Player
secondPlayer) {
return (firstPlayer.getAge() -
secondPlayer.getAge());
}
}
List<Player> hockeyteam = new ArrayList<>();
hockeyteam.add(new Player(12, "Zaeem", 32));
hockeyteam.add(new Player(18, "Samad", 29));
hockeyteam.add(new Player(07, "Basit", 33));
hockeyteam.add(new Player(10, "Hameed",
24));
System.out.println("Before Team: " +
hockeyteam + "\n---------------------");
Collections.sort(hockeyteam);
System.out.println("After Team :" +
hockeyteam);
PlayerAgeComparator compareAge = new
PlayerAgeComparator();
PlayerNameComparator compareName=new
PlayerNameComparator();
Collections.sort(hockeyteam, compareAge);
System.out.println("After Team (age): " +
hockeyteam);
Collections.sort(hockeyteam, compareName);
System.out.println("After Team (name): " +
hockeyteam);
Output:
Before Team: [Player{ rank:12, 'Zaeem', age: 32}, Player{ rank:18, 'Samad',
age: 29}, Player{ rank:7, 'Basit', age: 33}, Player{ rank:10, 'Hameed', age:
24}]
---------------------
After Team :[Player{ rank:7, 'Basit', age: 33}, Player{ rank:10, 'Hameed', age:
24}, Player{ rank:12, 'Zaeem', age: 32}, Player{ rank:18, 'Samad', age: 29}]
After Team (age): [Player{ rank:10, 'Hameed', age: 24}, Player{ rank:18,
'Samad', age: 29}, Player{ rank:12, 'Zaeem', age: 32}, Player{ rank:7, 'Basit',
age: 33}]
After Team (name): [Player{ rank:7, 'Basit', age: 33}, Player{ rank:10,
'Hameed', age: 24}, Player{ rank:18, 'Samad', age: 29}, Player{ rank:12,
'Zaeem', age: 32}]
§
Thank you
Learn on your own
java.util.PriorityQueue
Java Properties
Try to re-write the Employee class's hashCode
and equals methods following the given
guidelines of overloading these methods.
How to write your own list of objects that
implements Iterable interface.