Collections

Advanced Programming

SUT • Spring 2019

Contents

  • Containers

  • Collection

  • Set

  • Map

  • LinkedList

  • Iterator

Lists

Array

  • Suppose we have an array of students

    • Student[] students = new Student[34];

  • What if we do not know the array size?

    • A default initial size

  • What if we want to add more students to array?

    • Double the size of array

    • Copy old elements

  • What if we want to remove some students from array?

    • Nullify the element & shift the others

  • We need a dynamic array

Imagine if arrays was sth like:

Student[] students = new Student[0];
students.add(new Student("Ali Alavi"));
students.add(new Student("Taghi Taghavi"));
System.out.println(students[1]);
students.remove(0);

// But arrays are not so cute!

ArrayList

  • Java introduces Collection classes for this purpose

ArrayList students = new ArrayList();
students.add(new Student("Ali Alavi"));
students.add(new Student("Taghi Taghavi"));
students.remove(0);

Generic ArrayList

  • ArrayList is also a generic type



     
ArrayList<Student> students = new ArrayList<Student>();
students.add(new Student("Ali Alavi"));
students.add(new Student("Taghi Taghavi"));
students.remove(0);
students.remove(new Student("Ali Alavi"));
Student student = students.get(0);
System.out.println(student);

// ArrayList<T> implements generic interface List<T>

Interface

interface List<E>{
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    boolean add(E e);
    boolean remove(Object o);
    void clear();
    E get(int index);
    E set(int index, E element);
    void add(int index, E element);
    E remove(int index);
    int indexOf(Object o);
    int lastIndexOf(Object o);
    List<E> subList(int fromIndex, int toIndex);
}

Usage

ArrayList<String> list = new ArrayList<String>();
Scanner scanner = new Scanner(System.in);
while(true){
    String input = scanner.next();
    if(input.equalsIgnoreCase("exit"))
        break;
    list.add(input);
}
if(list.isEmpty()){
    System.out.println("No string entered");
}else{
    System.out.println("" + list.size() + 
                       " strings enetered");
    if(list.contains("Ali"))
        System.out.println("Ali Found!");
    
    for (String s : list) {
	System.out.println(s);
    }
}

ArrayList or Array? That is the question

  • Do we need a dynamic array?

    • Add

    • Remove

  • Performance issue

  • ArrayList is implemented using an array

Array to List

  • Guess how?

String[] strings = {"ali", "taghi"};

ArrayList<String> list = 
    new ArrayList<String>();
for (String string : strings) {
    list.add(string);
}

List to Array

  • Two methods:

    • Object[] toArray();

    • <T> T[] toArray(T[] a);

ArrayList<String> list = new ArrayList<String>();
Object[] array = list.toArray();
String[] array2 = list.toArray(new String[list.size()]);

Tell Me…

ArrayList<String> as;
ArrayList<Object> ao;
List<Object> lo;
List<String> ls;
  • True/False?

    • ArrayList<String> is subclass of List<String>

      • ls = as;

    • ArrayList<String> is subclass of ArrayList<Object>

      • ao = as;

    • ArrayList<String> is subclass of List<Object>

      • lo = as;

ArrayList Implementation

  • In the heart of an ArrayList, an array lives…

public class ArrayList<E> ... ,implements List<E>,...{
    private Object[] elementData;
    private int size;
    public boolean add(E e) {
	ensureCapacity(size + 1); 		
	elementData[size++] = e;
	return true;
    }
}

Tell Me…

  • Why toArray() returns Object[]?

Collection

  • Collection is super-class of many containers
public interface Collection<E>‌ {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    boolean add(E e);
    boolean remove(Object o);
    void clear();
    Object[] toArray();
    <T> T[] toArray(T[] a);
}

LinkedList

  • LinkedList and ArrayList are both subclass of List

  • ArrayList is implemented by an array

  • LinkedList is implemented by a doubly linked list

  • It is used like an ArrayList

    • Because they are brothers! (subclass of List)

Linked List

Doubly Linked List

LinkedList Example

List<String> list = new LinkedList<String>();
list.add("Ali");
list.add("Taghi");
System.out.println(list.get(0));
list.remove("Taghi");

for (String string : list) {
    System.out.println(string);
}

ArrayList vs. LinkedList

  • LinkedList stores two links for each element

  • if you want to do many insertions and removals in the middle of a list

    • a LinkedList is better

  • If not, an ArrayList is typically faster

Array, ArrayList and LinkedList

How to Test Performance?

long start = System.currentTimeMillis();

doSomthing();

long end = System.currentTimeMillis();

System.err.println(end - start);

Set

Set

  • A set is a an unordered list of disjoint elements
{1,2,3,1,4,2} = {4,3,2,1}

set.add(1)
set.add(2)
set.add(3)
set.add(1)
set.remove(1)
Set == {3,2}

Set

  • A set is a list with no duplicate

  • Suppose we want to implement such a class

  • How?!

Set Implementation

class Set<E> extends ArrayList<E>{
    public boolean add(E e) {
	if(!contains(e))
	    return super.add(e);
        return false;
    }

    public boolean add(int index, E e) {...}
}

Set and equals() Method

  • When set.add(value) is invoked

  • It checks whether there is any element equal to value

  • If any equal element found, add will return

  • We should implement appropriate equals() method

  • equals() is invoked implicitly

HashSet

  • Set is an interface

  •     public interface Set<E> extends Collection<E>

  • HashSet is one of its (popular) implementations

  • Set and HashSet are generic classes

  •     public class HashSet<E> implements Set<E>

HashSet Example

Set<String> set= new HashSet<String>();
set.add("Ali");
set.add("Taghi");
set.add("Ali");
for (String string : set) {
    System.out.println(string);
}

HashSet Example

Set<Student> set= new HashSet<Student>();
set.add(new Student("Ali"));
set.add(new Student("Taghi"));
set.add(new Student("Ali"));
set.remove(new Student("Taghi"));
for (Student student : set) {
    System.out.println(student);
}

Set or List?

  • List provides access via an index

    • Set does not

  • List is ordered

  • Set checks for duplicates

    • List is (usually) better in performance

    • Set may be better in memory consumption

  • Should we allow duplicates?

    • If not, use sets

  • HashSet is not implemented by a List

Map

Map

  • Map is not a collection

  • Map is a table

  •         public interface Map<K,V>

  • Map<K, V> is something like a List<Pair<K,V>>

  • First element of each pair is called the key

  • Second element of each pair is called the value

  • Duplicate for keys is not allowed

  • Duplicate for values is possible

Example

Command Keys Values
map.put(87300876, “Ali Alavi”) 87300876 Ali Alavi
map.put(87234431, “Taghi Taghavi”) 87300876 Ali Alavi
87234431 Taghi Taghavi
map.put(87300876, “Naghi Naghavi”) 87300876 Naghi Naghavi
87234431 Taghi Taghavi

Interface

public interface Map<K,V> {
    int size();
    boolean isEmpty();
    boolean containsKey(Object key);
    boolean containsValue(Object value);
    V get(Object key);
    V put(K key, V value);
    V remove(Object key);
    void putAll(Map<? extends K, ? extends V> m);
    void clear();
    Set<K> keySet();
    Collection<V> values();
    Set<Map.Entry<K, V>> entrySet();
    interface Entry<K,V> {
	K getKey();
	V getValue();
	V setValue(V value);
    }
}

HashMap

  • Map is an interface

  •     public interface Map<K,V>

  • HashMap is one of its (popular) implementations

  •     public class HashMap<K,V> implements Map<K,V>

HashMap Example

Map<Integer, String> map =  new HashMap<>();
map.put(87300876, "Ali Alavi");
map.put(87234431, "Taghi Taghavi");
map.put(87300876, "Naghi Naghavi");
String name = map.get(87300876);
System.out.println(name);

HashMap Example

Map<Student, Double> map = new HashMap<>();
map.put(new Student("Ali Alavi"), new Double(18.76));
map.put(new Student("Taghi Taghavi"), new Double(15.43));
map.put(new Student("Naghi Naghavi"), new Double(17.26));
map.put(new Student("Naghi Naghavi"), new Double(15.26));
map.remove(new Student("Naghi Naghavi"));

Double average = map.get(new Student("Taghi Taghavi"));
System.out.println("Avg of Taghi=" + average);
for(Student student : map.keySet()){
    System.out.println(student.toString());
}

Double totalSum = 0.0;
for(Double avg : map.values()){
    totalSum += avg;
}

System.out.println("Total Average = " + (totalSum/map.size()));

Iterator

Iterator

  • Iterator is a mechanism for walking on elements of a collection

  • Before foreach (before Java5) it was the only mechanism

  • iterator() is declared in Iterable interface

  • In fact for-each is applicable on any Iterable object

Iterator

public interface Iterable<T> {
    Iterator<T> iterator();
}

public interface Collection<E> extends Iterable<E> {…}

Iterator Class

ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(4);
arrayList.add(5);
for (Integer next : arrayList) {
    System.out.println(next);
}

Iterator<Integer> iterator = arrayList.iterator();
while(iterator.hasNext()){
    Integer next = iterator.next();
    System.out.println(next);
}

Concurrent Modification

  • Suppose some processes are modifying the same collection

  • Java containers have a mechanism to prevent it

  • Suppose you’re in the middle of iterating through a container

  • And then some other process steps in and changes an object in that container

    • Insert, remove, …

  • there are many scenarios for disaster.

    • Maybe you’ve already passed that element in the container

    • Maybe it’s ahead of you

    • Maybe the size of the container shrinks after you call size( )

Fail Fast Aspect

  • If a collection is modified by one of its methods after an iterator is created for that collection

  • The iterator immediately becomes invalid

  • Any operations performed with the iterator after this point throw ConcurrentModificationExceptions

  • For this reason, iterators are said to be “fail fast

ConcurrentModificationException

public class FailFast {
    public static void main(String[] args) {
	Collection<String> c = new ArrayList<String>();
	Iterator<String> it = c.iterator();
	c.add("An object");
	String s = it.next(); // Exception line 
    }
}

ConcurrentModificationException

ArrayList<Integer> list = new ArrayList<Integer>();

list.add(1);
list.add(2);
list.add(3);
list.add(4);

for (Integer integer: list) // Exception line 
    if(integer.equals(2))
        list.remove(integer);

Arrays

  • A utility class with many useful static methods
  • For arrays
  • With methods for
    • Copy
    • Fill
    • Sort
    • Search

Arrays

Long[] array = new Long[100];
Arrays.fill(array, 5);
Long[] copy = Arrays.copyOf(array, 200);
//An unmodifiable list:
List<Integer> asList = Arrays.asList(1, 2 , 3, 4);
List<Long> asList2 = Arrays.asList(array);
Arrays.sort(array);

Collections

  • A utility class for collections
    • Copy
    • Fill
    • Sort
    • Search

Collections

TODO

  • Write the method

  •         removeAlis(List<String> names)

  • It takes a List<String> as parameter

  • Removes all the elements which start with “Ali”

Bad Implementation

static void removeAli(List<String> list){
    for (String string : list)
	if(string.startsWith("Ali"))
	    list.remove(string);
}

Good Implementation

public static void removeAli(ArrayList<String> list){
    Iterator<String> iterator = list.iterator(); 
    while(iterator.hasNext()) {
	String string = iterator.next();
	if(string.startsWith("Ali"))
	    iterator.remove();
    }
}

Good Implementation

public static void removeAli(ArrayList<String> list){
    for (Iterator<String> iterator = list.iterator(); 
        iterator.hasNext(); ) {
        String string = iterator.next();
        if(string.startsWith("Ali"))
	    iterator.remove();
    }
}

Another Correct Implementation

public static void removeAli(ArrayList<String> list){
    for (int i = list.size()-1; i >= 0; i--) 
	if(list.get(i).startsWith("Ali"))
	    list.remove(i);
}

hashCode()

  • hashCode() is one of Object methods

    • like equals, toString and finalize

  • It creates a hash from the object

  • Used in classes like HashMap and HashSet for faster retrieval

Title Text

Collections

By Behnam Hatami

Collections

Collections / Advanced Programming Course @ SUT, Spring 2019

  • 1,159