The document discusses generics and collections in Java. It explains key interfaces like List, Set, and Map. It describes how generics allow type-safety by restricting the types of objects that can be added to collections. The use of raw types can cause exceptions while generics prevent errors at compile time.
The document discusses generics and collections in Java. It explains key interfaces like List, Set, and Map. It describes how generics allow type-safety by restricting the types of objects that can be added to collections. The use of raw types can cause exceptions while generics prevent errors at compile time.
Introduction (contd.) • The classes in java.util package use collections, i.e. a group of objects. – Collection Classes work on objects, i.e. they store/retrieve objects. – Primitives cannot be directly stored and retrieved in collections. – Wrapper classes representing primitives were created in java.lang package to work with collections.
Introduction (contd.) • The java.util package has an interface named Collection. A collection supports a group of objects. • A collection may be – ordered/unordered as well as some collections – may possess duplicates while others may not. • This collection interface has sub-interfaces like Set, List, Queue, etc. – These interfaces have concrete subclasses like LinkedList, Stack, Vector, etc. • Besides Collection, we have shown another interface Map which work on pairs – Key/value pairs. – This interface has a nested interface named Entry.
Collection Inheritance hierarchy • The java.lang.Iterable interface was added by JDK 1.5 and Collection interface was made to inherit it so that the objects can be iterated using a for-each loop. – This interface provides a method named iterator() that returns an Iterator object to iterate all the objects in the collection. • The Collection interface is implemented by an abstract class AbstractCollection, which is the parent of all the collection classes • List interface refers to an ordered but duplicate collection of objects.
Collection inheritance hierarchy • We refer to a List as ordered because the user has full control over the order in which an object is inserted into the list. – The top level class for List interface is an abstract class AbstractList (which is a subclass of AbstractCollection). – AbstractList implements almost all the methods of List interface and has three subclasses AbstractSequentialList, ArrayList, and Vector. – LinkedList class is subclass of AbstractSequentialList and its definition has been modified in JDK 1.6 to implement the Deque interface. • Stack is a subclass of the Vector class.
Queue interface • Queue interface was added in JDK 1.5 to support the data structure. – Queue operates in FIFO (first in first out fashion). – Elements inserted into collection first are removed from the collection first. – These queues support operations to add/remove/examine elements at both ends (head and tail) of the queue.
Set Interface • Set is a collection that does not contain duplicate objects. • This interface is implemented by an abstract class AbstractSet which implements some of the methods of Set interface. – The concrete classes, HashSet, EnumSet, etc., are subclasses of AbstractSet. – This interface is inherited by SortedSet interface to access the element in a sorted order (ascending). – The class TreeSet inherits the SortedSet interface and the AbstractSet class.
Map interface • Map interface provides mapping of key/value pairs. – This key/value pairs are unique. – A static inner interface named Entry is declared inside the Map interface for referring to each key/value pair. – This Map is inherited by an interface SortedMap to access the elements stored in Map in a sorted order. – AbstractMap class inherits the Map interface. – This class is inherited by concrete classes like HashMap; EnumMap, etc. – TreeMap also inherits this class as well as the interface SortedMap. • Most of the interfaces and classes in the java.util package use Generics.
Generics • were added in Java 5 to provide strict type checking at compile time. • allows same class to be used by many different collection of objects like String, Integer, etc. • Consider the following example where we have created three classes named A, B and GenericTest. – The class GenericTest has a collection of ArrayList class to hold objects. – We have placed the objects of A and B in it and later we try to retrieve them.
GenericTest.java GenericTest.java:15: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.List v.add(new A()); ^ GenericTest.java:16: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.List v.add(new A()); ^ GenericTest.java:17: warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.List v.add(new B()); ^ 3 warnings
The Output • C:\javabook\programs\chap 10>java GenericTest Class A Object Class A Object Exception in thread “main” java.lang.ClassCastException: B cannot be cast to A at GenericTest.main(GenericTest.java:21)
Problem & Solution • The problem occurred because there was no restriction on the type of objects that can be put into a collection. – In the earlier example we had put objects of A as well as B into the collection and we are casting all objects into A which raised an alarm at run time. • It would be much better to check at compile time what goes into a collection so that no exception occurs at run time. – If we could ensure only objects of A should go into the collection then the problem can be solved and that’s where Generics help.
Problem & Solution • Most of the interfaces/ classes as well as some of the methods have been modified to use Generic syntax. The generic declaration of List is – List<E> v=new ArrayList<E>(); – This E has been replaced by A as shown. Single Capital character are used to denote generic Formal parameterized types – List<A> v=new ArrayList<A>(); //List of objects of A (actual parameter) – The name placed in the angle brackets (commonly known as specifying parameterized type) is class name whose objects we want to put into a collection.
Problem & Solution – Now this collection will not contain objects of class other than the class-name mentioned in the angle brackets. – For e.g. If we try to insert an object of type B into collection ‘v’(after using parameterized types), a compile time error results. • The point worth mentioning here is that the List now contains only objects of type ‘A’ and the compiler assures us of this. • So is the cast on Line 14 really required? – Well logically it should not be required but if you remove the cast on Line 14, the compiler complains about it. – Why?
Problem & solution – The reason is we did parameterize the List but we did not parameterize the Iterator which continued to return an object of type Object on invocation of next method. • Similar to List, Iterator also uses the Generic parameterized types. So if we change the Line 12 as shown the problem gets solved and the cast can now be removed safely. – Iterator<A> en=v.iterator(); – while(en.hasNext()){ – A o=en.next(); – System.out.println(o);}
Wildcards • In the Example 10.2, if we change Line 13 as follows – List<Object> l = pag.getList(); • Anybody would consider it legal arguing – Object is the super class of String so the assignment should be legal, but that’s not the case. A List of Object is not a List of String. Why? • Consider the case if a List of String is a List of Object that means the above modified Line 13 is supposedly working. • Then we could also insert lines in the program to add objects of type Object to the List. Now when we retrieve them and try to store in a List of String it gives me a Cast exception because we are trying to store an Object into a String. • So a List of Object is not a List of String and vice-versa.
Wildcards (contd.) • If you want to be flexible in using the classes as they were used earlier i.e. without parameterized types then – either you will have to suppress the warnings or – you will have to be rigid in the using Collection of a particular type. • we can use the Collection to hold different types of object not just a particular type using Generic syntax. This is possible with the help of Wildcards i.e. ‘?’. • Let us take a look at how wildcards can be used.
Example (contd.) public static void main(String args[]) { ParamArgsGeneric pag=new ParamArgsGeneric(); List<?> l=pag.getList(); pag.print(l); // another List created and passed to print() List<Integer> li=new ArrayList<Integer>(); li.add(new Integer(1)); li.add(new Integer(2)); li.add(new Integer(3)); pag.print(li); }}
• Can we re-write – List<String> l=new ArrayList<String>(); – as: – List<?> l=new ArrayList<String>(); • It is illegal. • For a very simple reason, that a List of unknowns need not necessarily be a List of String. • So wildcards can be used in passing parameterized types as arguments / return types as well as capturing the return values from the methods.
Bounded Wildcard • Bounded wildcards place certain restriction on the type of objects that a collection can hold. For e.g. ? extends X • ? Specifies unknown type, but this unknown type will be a subclass of X. • So in this case we know that this unknown type is either X or one of its subclasses. • In the following example we have created three classes A, B and C. – class B inherits from A. – C is an independent class. – Now let us see how bounded wildcards place a restriction on collection of objects.
Example import java.util.*; class A { public String toString(){return “class A”;}} class B extends A { public String toString(){return “class B”;}} class C {} class BoundedWildcard{ void print(List<? extends A> c){ Iterator<?> i=c.iterator(); while(i.hasNext()) System.out.println(i.next()); }
Define your own Generic class • You can create your own classes that use generic syntax. • For using a Generic syntax in your classes, a normal naming convention should be followed for specifying parameterized types. • The naming convention is a single Capital Letter used for specifying parameterized types. – For e.g. T is for specifying any type. – The letter E has been used in the java Collection API extensively to denote Collection elements. – In Map the alphabet K for keys and V for values.
Your turn • Let us take a quick recap of the concepts: • Queue • Stack • What are Generics? • What is the use of Wildcards in generics? • What are bounded wildcards?
Linked List • Linked list is a fundamental data structure that contains records. – A record contains data as well as a reference to the next record. – A record can be inserted or removed at any point in the Linked List. – In comparison to normal arrays which allow random access, Linked lists allow sequential access. – To support this data structure, java has a class named LinkedList. • LinkedList is a collection class that can act as a stack, queue as well as a double-ended queue. – LinkedList permits null to be added to the list.
Set • Set is a collection that does not contain duplicates. – Set collection in java.util models the mathematical concept set. – The concepts of Union, Intersection and difference of a set are available in the Set interface and supported by its subclasses. • Two subclasses exists – HashSet and TreeSet. – TreeSet is a sorted collection as it inherits the SortedSet interface (sub-interface of Set) whereas – HashSet is not a sorted collection. • HashSet uses the concept of Hashing.
HashSet • This class can be used for effectively storing and retrieving the elements but the order is not guaranteed by this class. • In case you need to retrieve the elements in a sorted order use TreeSet class. • HashSet permits null to be added to the collection. • Let us take an example to demonstrate HashSet class.
Example (contd.) System.out.println(“Iterating contents of Hash Set one by one”); for(String s:hs) System.out.println(“\t”+s); System.out.println(“Size of Hash Set: ”+hs.size()); System.out.println(“null removed: ”+hs.remove(null)); System.out.println(“Hash Set: ”+hs); System.out.println(“check whether Set contains C :”+hs.contains(“C”)); HashSet<String> hs1=new HashSet<String>(); hs1.add(“D”); hs1.add(“B”); hs1.add(“E”);
Example (contd.) /*subset*/ System.out.println(“hs: ”+hs); System.out.println(“hs1: ”+hs1); System.out.println(“hs1 is a subset of hs: ”+hs.containsAll(hs1)); /*Intersection*/ hs.retainAll(hs1); System.out.println(“Intersection of hs and hs1: ”+hs); /*Difference*/ hs.removeAll(hs1); System.out.println(“Difference of hs and hs1: ”+hs); /*Union*/ System.out.println(“Hash Set to be united with previous set: ”+hs1); hs.addAll(hs1); System.out.println(“Union of hs and hs1: ”+hs);}}
The Output C:\javabook\programs\chap 10>java HashSetDemo Hash Set: [null, D, E, A, B, C] Re-adding C to set: false Iterating contents of Hash Set one by one null D E A B C Size of Hash Set: 6 null removed: true
The output (contd.) Hash Set: [D, E, A, B, C] check whether Set contains C :true hs: [D, E, A, B, C] hs1: [D, E, B] hs1 is a subset of hs: true Intersection of hs and hs1: [D, E, B] Difference of hs and hs1: [] Hash Set to be united with previous set: [D, E, B] Union of hs and hs1: [D, E, B]
TreeSet • offers a strict control over the order of elements in the collection. • The collection is a sorted collection. • may not offer you the best performance in terms of retrieving elements speedily (use HashSet instead of TreeSet). • does not permit null in the collection.
TreeSet Example import java.util.*; class TreeSetDemo{ public static void main(String args[]){ TreeSet<String> ts=new TreeSet<String>(); ts.add(“D”); ts.add(“B”); ts.add(“A”); ts.add(“C”); ts.add(“A”); ts.add(“C”); //ts.add(null); does not accepts null values for(String s:ts) System.out.println(s); System.out.println(“TreeSet: “+ts); System.out.println(“First element of TreeSet: “+ts.first()); System.out.println(“Last element of TreeSet: “+ts.last()); System.out.println(“Size of TreeSet: “+ts.size());}}
The Output C:\javabook\programs\chap 10>java TreeSetDemo A B C D TreeSet: [A, B, C, D] First element of TreeSet: A Last element of TreeSet: D Size of TreeSet: 4
Maps • Map allows unique Key/value pairs to be added. • A Map collection stores key along with their associated values. • These keys in Map are unique. • Map does not allow null key and values. • Two subclasses of Map interface – HashMap and – TreeMap
HashMap • HashMap, alike HashSet uses hashing as a technique to store Key/value pairs so that the values can be searched efficiently according to the key. • There order is not guaranteed by HashMap. • The HashMap does not allow null key and null value pair to be stored.
Your turn • Let us take a recap of the concepts: • What are Linked List? • What are the essential qualities of Set? – HashSet – TreeSet • What are the essential qualities of Map? – HashMap – TreeMap
Collections class • Collections class contains a number of static methods that operate on Collection – like copy a Collection, – reversing the elements of a Collection, – replacing an element with another and soon. • Let us take an example.
Collections class Example import java.util.*; public class CollectionsDemo { public static void main(String[] args) { List<String> l = new LinkedList<String>(); l.add(“Ignorance”); l.add(“is”); l.add(“a”); List<String> sb = new LinkedList<String>(); sb.add(“Bliss”); List<String> srch =new LinkedList<String>(); srch.add(“Bliss”); System.out.println(“Elements in list : “ + l); // create a copy of defined list and print objects of copy list. Collections.copy(l,sb); System.out.println(“copy of list : “ + l); // find and display index of first occurrence of sublist in the list. System.out.println(“First index of ‘Bliss’: “ + Collections.indexOfSubList(l, srch));
Collections class Example (contd.) // replace all objects in list by a new given object. Collections.replaceAll(l, “Bliss”, “welcome”); System.out.println(“After replace all ‘Bliss’: “ + l); // list in reverse order. Collections.reverse(l); System.out.println(“List in reverse order: “ + l); // swaps specified element with element at 1st(second) position Collections.swap(l, 1, l.size() - 1); System.out.println(“List after swapping : “ + l); // Replace all the element with given element using fill() Collections.fill(l, “Bliss”); System.out.println(“After filling all ‘Bliss’ in list : “+ l); // getting an enum type of specified list through enumeration(). Enumeration<String> e = Collections.enumeration(l); while (e.hasMoreElements()) System.out.println(e.nextElement()); }}
The Output C:\javabook\programs\chap 10>java CollectionsDemo Elements in list : [Ignorance, is, a] copy of list : [Bliss, is, a] First index of ‘Bliss’: 0 After replace all ‘Bliss’: [welcome, is, a] List in reverse order: [a, is, welcome] List after swapping : [a, welcome, is] After filling all ‘Bliss’ in list : [Bliss, Bliss, Bliss] Bliss Bliss Bliss
Legacy classes • Vector and ArrayList classes are both used to support the functionality of dynamic arrays. • Array cannot grow/shrink in size so these classes have been provided in java.util package to support Collection that can grow/shrink in size. • Vector is synchronized whereas ArrayList is not. – That means a Vector collection is thread-safe when accessed by multiple threads. – On the other hand an ArrayList offers better performance as it is not synchronized.
Legacy classes • Vector<String> v = new Vector<String>(); • The elements can be added to the Vector using add(E e) method as shown • v.add(“One”); • v.add(“Two”);
Legacy Interfaces • Enumeration is a Legacy interface. • work with classes like Vector. • Suppose the Vector contains Integer objects. – To iterate through the Collection we obtain an Enumeration by calling the elements() method of the Vector object. – This Enumeration has two methods • hasMoreElements() that returns a boolean value to indicate that the collection has more values and the • nextElement() returns the next Element in the collection. – Enumeration<Integer> en=v.elements(); – While(e.hasMoreElements()) – System.out.println(e.nextElement());
Random class • Used to generate random numbers – Random r = new Random(); – Random r = new Random(seed); – A seed is a number used to initialize a pseudorandom number generator • int randomInt = r.nextInt(n); – generate random integers between 0 and some limit (n-1).
Random class Example • Random randomGenerator = new Random(); • for (int i = 1; i <= 6; ++i) { • int randomInt = randomGenerator.nextInt(6)+1; • System.out.println(i+ ". Integer Random Number: "+randomInt); } • double randomDouble = randomGenerator.nextDouble(); • System.out.println("Double Random Number: "+ randomDouble); • float randomFloat = randomGenerator.nextFloat(); • System.out.println("Float Random Number: "+randomFloat);
Runtime class • The Runtime class is used to know the information about free memory and total memory. • In addition to that it is also used for executing additional processes. • The current runtime instance is obtained using a static method of the Runtime class, i.e., getRuntime()
Reflection API • Before you can use reflection API on a class you need to obtain its java.lang.Class object. • A class object can be obtained in two ways: – Class cl = MyClass.class; where MyClass is the name of the class – Class cl = Class.forName(cn); where cn is the name of the class passed as a string
SUMMARY • This chapter focused on java.util package: – Collection (a.k.a bag of objects) interfaces – Generics – data structure concepts like Linked list, stack, queues, trees, hashing e.t.c. – classes like LinkedList, Stack, HashSet, TreeSet e.t.c – a Map interface. – Dynamic Array functionality: ArrayList and Vector. – Legacy Interface Enumeration and newer Iterator interface :for iterating over the collection of objects. – Random and Runtime class – Observer and Observable – Reflection API