Module_1
Collections & Generics
Represent the values using variables
Using Individual Variable Using Array Variable
int x= 10; Employee[] e =
new Employee[1000];
int y=20; Limitations:
int z=30; - Fixed Size
. - Only Homogeneous Data
E.g. e[0] = new
. Employee();
. e[1] = new Person();
What if total - No underlying Standard
values are Data Structure and
readymade
25000?
method support
Collections Framework
Why Collections Framework?
• Does your program require data more than single
element?
• Making use of Data Structure
• A Data Structure is a programming construct that
contains more than one element as a separate
accessible unit
• In Object Oriented Terms, A data structure is an
aggregation and the elements are objects
• Eg: DS to represent Students in a class, Items in a
purchase order, accounts in bank
Why Collections Framework? (2)
• Collections in Java are aggregations
• Collections framework consists;
- Interfaces that define the behavior of
collections (methods to add and remove)
- Concrete classes that provide general
purpose implementations
- Abstract classes that implement the
interfaces
• Elements in collections must have reference
types
Arrays vs Collections
Arrays Collections
• Fixed in size • Growable
• Not recommended if Memory • Recommended if Memory is a
is a concern concern
• Recommended if • Not Recommended if
Performance is a concern
performance is a concern
• Can hold only Homogeneous
elements • Both Homogeneous and
• No underlying data structure Heterogenous
• Every class is Based on some
• Can hold both primitives and standard data structure
Object types • Can only Hold Objects
Fundamental change by Generics
• All collections are now generic
• Some methods take generic type parameters
• Generics added the previously missing feature
called type safety
• Run time mismatch errors are avoided
• Entire collections framework was
reengineered
Collection hierarchy
Collection hierarchy
The Collection Interfaces
The Collection Classes
Accessing a Collection via an
Iterator Interface
• Means to enumerate the contents of a Collection
• Use of Iterator or the ListIterator interface
• Enables you to cycle through a collection, obtain
and removal of elements
• ListIterator allows bidirectional traversal of a list
• List and ListIterator are generic interfaces:
- interface Iterator<E>
- interface ListIterator<E>
List Interface
• List is a child interface of Collection
• List is used to represent the group of
individual objects as a single entity where;
- Duplicate elements are allowed
- Insertion order is preserved
The ArrayList Class
• ArrayList class extends AbstractList and implements the List
interface.
• ArrayList is a generic class that has this declaration:
class ArrayList<E>
• E specifies the type of objects that the list will hold.
• ArrayList supports dynamic (Resizable or Growable) arrays that
can grow as needed
• Duplicates are allowed
• Insertion order is preserved
• Heterogeneous objects are allowed (Except TreeSet & TreeMap)
• Null insertion is possible.
• Default initial capacity is 10
• Formula for new capacity = (Current Capacity * 3/2)+1
Obtaining an Array from an ArrayList
• To obtain an actual array that contains the
contents of the list by calling toArray() defined by
Collection
• Reasons for conversion
- To obtain faster processing times for certain
operations
- To pass an array to a method that is not
overloaded to accept a collection
- To integrate collection-based code with legacy
code that does not understand collections
The LinkedList Class
• LinkedList class extends abstractSequentialList
and implements the List, Deque, and Queue
interfaces
• LinkedList is a generic class that has this
declaration:
class LinkedList<E>
• E specifies the type of objects that the list will
hold
ArrayList Vs LinkedList
ArrayList LinkedList
• Best when frequent operation • Best when frequent operation is
is retrieval insertion or deletion
• Worst when frequent • Worst when frequent operation
operation is insertion or is retrieval
deletion
• Underlying data structure is • Underlying data structure
resizable or growable (index is Double Linked List (node
based) based)
• Implements RandomAccess • Doesn’t implement
Interface RandomAccess Interface
• Less memory occupation
• Require more memory
Set Interface
• Defines a set
• Extends Collection interface
• Doesn’t allow duplicate elements
• Insertion order is not preserved
• Allows to store at most one null value
• No additional methods of its own
• Set is a generic interface:
interface Set<E>
• E specifies the type of objects that the set will
hold.
HashSet class
• Implements Set interface
• Uses Hash table for storage
• Contains unique elements only
• Insertion order is not preserved
• The class permits null element
• Default capacity of 16 and load factor is 0.75
• It is not synchronized
TreeSet class
• Implements Set interface
• Uses a tree for storage of data
• Natural sorted order is maintained
• Contains unique elements
• Doesn’t allow null
• It is not synchronized
• All elements must implement comparable
interface
The Map Interfaces
The Map Classes
The HashMap Class
• HashMap class extends AbstractMap and implements the
Map interface
• It uses a hash table to store the map
• allows the execution time of get( ) and put( ) to remain
constant even for large sets
• HashMap is a generic class that has this declaration:
class HashMap<K, V>
• K specifies the type of keys, and V specifies the type of
values
• Performance affecting factors are initial capacity & Load
factor (Default LF is 0.75)
• Default initial capacity is 16
• Rehashed if crosses the threshold of (Initial capacity * LF)
TreeMap class
• Allows to store key value pairs in sorted order
• Sorted according to the natural ordering of
keys
• Contains only unique elements
• Class cannot have null key
• Class can have multiple null values
• It is not a synchronized class
• Maintains ascending order
Vector
• Vector implements a dynamic array
• It is similar to ArrayList, but with two differences:
1) Vector is synchronized,
2) It contains many legacy methods that
duplicate the functionality of methods
defined by the Collections Framework
• Vector is declared like this:
class Vector<E>
• E specifies the type of element that will be
stored.
Why Generics..?
• Compile time bugs are easier to detect
• Creation of classes, interfaces, and methods that
will work in a type-safe manner with various kinds
of data.
• The Collections Framework has been most
significantly affected by generics
• Collections Framework defines several classes, such
as lists and maps, that manage collections
• A collection is a group of objects
• With generics added, the collection classes can
now be used with complete type safety
What Are Generics?
• Generics means parameterized types
• Generics enable you to create classes, interfaces,
and methods in which the type of data upon
which they operate is specified as a parameter
• A class, interface, or method that operates on a
parameterized type is called generic class, generic
interface or a generic method
• A single class that automatically works with the
different types of data
• Introduced in JDK 5
What Are Generics? (2)
• Pre-generics code is designed to hold
java.lang.Object (any type of java objects)
• Pre-Generics code has
- problem of type safety
- requirement of type casting
• Use of Generics solves the above problem
• All casts are employed automatically and
implicitly
• Generics makes your code re-usable
What is type safety?
• Case 1: Storage of Employee Names in Array
String [] empName = new String[1500];
empName[0]= “Ramesh”;
empName[1]= “Suresh”;
empName[2]= “Rakesh”;
empName[3]= new Integer(20);
empName[4]= “Mukesh”;
What is type safety? (2)
Conclusion:
• Arrays are type safe i.e. we can give the
guarantee for the type of elements present
inside array.
• If our application requirement is to hold only
string type of objects we can opt for String
array.
• By mistake if we are try to add any other type
of objects we will get Compile time Error
What is type safety? (3)
• Case 2: Storage of Employee Names in ArrayList
ArrayList empName = new ArrayList();
empName.add(“Ramesh”);
empName.add(“Suresh”);
empName.add(new Integer(10));
empName.add(“Mukesh”);
String name1= (String)al.get(0); // Retrieving data
String name2= (String)al.get(1); // Retrieving data
String name3= (String)al.get(2); // Retrieving data
What is type safety? (4)
Conclusion:
• Collections are not type safe i.e. we can’t give the
guarantee for the type of elements present inside
collection
• If our application requirement is to hold only
String type of objects and if we opt for ArrayList,
and by mistake if we try to add any other type of
Object we won’t get any Compile time error but
the program may fail at run time
What is type casting?
• Case 1:
String[] empName= new String[100];
empName[0]=“Ramesh”;
empName[1]=“Amit”;
String s1= empName[0]; // Retrieving data
String s2= empName[1]; // Retrieving data
• Conclusion:
No Error. Type casting is not required.
What is type casting? (2)
• Case 2:
ArrayList empName= new ArrayList();
empName.add(“Ramesh”);
empName.add(“Amit”);
String s1= empName.get(0); // Retrieving data
String s2= empName.get(1); // Retrieving data
• Conclusion:
- Compile time error.
- Type casting is required.
• Solution:
String s1= (String)empName.get(0);
String s2= (String)empName.get(1);
Boxing and UnBoxing
// Demonstrate a type wrapper.
class Wrap {
public static void main(String args[]) {
Integer iOb = new Integer(100);
int i = iOb.intValue();
System.out.println(i + " " + iOb); // displays 100
100
}
}
AutoBoxing and Auto-unboxing
• Integer iOb = 100; // autobox an int
• int i = iOb; // auto-unbox
// Demonstrate autoboxing/unboxing.
class AutoBox {
public static void main(String args[]) {
Integer iOb = 100; // autobox an int
int i = iOb; // auto-unbox
System.out.println(i + " " + iOb); // displays 100 100
}
}
Generic Types
• A generic type is a generic class or
interface that is parameterized over types.
• Eg:
public class Box
{
private Object o;
public void set(Object obj) {
o = obj;
}
public Object get() {
return o;
}
}
Generic Types (2)
• A generic class is defined with the following
format:
class name<T1, T2, ..., Tn> { /* ... */ }
• Eg: A Generic Version of the Box Class
public class Box<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
The General Form of a Generic Class
• The generics syntax shown in the preceding
examples can be generalized. Here is the
syntax for declaring a generic class:
class class-name<type-param-list > { // …
• Here is the full syntax for declaring a reference
to a generic class and instance creation:
class-name<type-arg-list > var-name =
new class-name<type-arg-list >(cons-arg-list);
Invoking and Instantiating a Generic
Type
• An invocation of a generic type is generally
known as a parameterized type
• Generic Type invocation
Declaration:
- Box<Integer> integerBox;
Instantiation:
- Box<Integer> integerBox = new Box<Integer>();
OR
- Box<Integer> integerBox = new Box<>();
Multiple Type Parameters
public interface Pair<K, V> {
public K getKey();
public V getValue();
}
public class OrderedPair<K, V> implements Pair<K, V> {
private K key;
private V value;
public OrderedPair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
}
Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8);
Pair<String, String> p2 = new OrderedPair<String, String>("hello", "world");
A Simple Generics Example
// Here, T is a type parameter that
// will be replaced by a real type
// when an object of type Gen is created.
class Gen<T> {
T ob; // declare an object of type T
// Pass the constructor a reference to
// an object of type T.
Gen(T o) {
ob = o;
}
// Return ob.
T getob() {
return ob;
}
A Simple Generics Example
// Show type of T.
void showType() {
System.out.println("Type of T is " +
ob.getClass().getName());
}
}
A Simple Generics Example
// Demonstrate the generic class.
class GenDemo {
public static void main(String args[]) {
// Create a Gen reference for Integers.
Gen<Integer> iOb;
// Create a Gen<Integer> object and assign its
// reference to iOb. Notice the use of autoboxing
// to encapsulate the value 88 within an Integer object.
iOb = new Gen<Integer>(88);
// Show the type of data used by iOb.
iOb.showType();
A Simple Generics Example
// Get the value in iOb. Notice that
// no cast is needed.
int v = iOb.getob();
System.out.println("value: " + v);
System.out.println();
// Create a Gen object for Strings.
Gen<String> strOb = new Gen<String> ("Generics Test");
// Show the type of data used by strOb.
strOb.showType();
// Get the value of strOb. Again, notice
// that no cast is needed.
String str = strOb.getob();
System.out.println("value: " + str);
}
}
Type Parameter Naming Conventions
• Type parameter names are single, uppercase letters
• The most commonly used type parameter names
are:
▪ E - Element (used extensively by the Java
Collections Framework)
▪ K - Key
▪ N - Number
▪ T - Type
▪ V - Value
▪ S,U,V etc. - 2nd, 3rd, 4th types
Generics Work Only with Reference
Types
• Type argument passed to the type parameter
must be a reference type
• You cannot use a primitive type, such as int or
char
• The following declaration is illegal:
Gen<int> intOb = new Gen<int>(53);
// Error, can't use primitive type
Generic Types Differ Based on Their
Type Arguments
• A reference of one specific version of a generic
type is not type compatible with another
version of the same generic type
• Ex: iOb = strOb; // Wrong!
• This is part of the way that generics add type
safety and prevent errors
How Generics Improve Type Safety
• Generics automatically ensure the type safety
of all
• Generics eliminate the need for you to enter
casts and to type-check code by hand
• The ability to create type-safe code in which
type-mismatch errors are caught at compile
time is a key advantage of generics
• Through generics, run-time errors are
converted into compile-time errors
Bounded Types in Generics
• Whenever you want to restrict the type
parameter to subtypes of a particular class
you can use the bounded type parameter.
• If you just specify a type (class) as bounded
parameter, only sub types of that particular
class are accepted by the current generic class
• These are known as bounded-types in
generics in Java.
Defining bounded-types for
class
• You can declare a bound parameter just
by extending the required class with the
type-parameter, within the angular braces
as,
class Sample <T extends Number>
• If you pass other types as parameters to
this class (String for example) a compile
time error will be generated.
Wildcards in Generics
• Instead of the typed parameter in generics (T)
you can also use “?”, representing an unknown
type
• The question mark (?) is known as
the wildcard in generic programming
• The wildcard can be used in a variety of situations
such as the type of a parameter, field, or local
variable
• Java provides 3 types of wild cards namely upper-
bounded, lower-bounded, un-bounded.
Upper Bounded Wildcards
• These wildcards can be used when you want
to relax the restrictions on a variable.
• For example, say you want to write a method
that works on List < Integer >, List < Double
>, and List < Number >
• Example:
public static void add(List<? extends Number> list)
Lower Bound Wildcards
• If we use the lower-bounded wildcards you
can restrict the type of the “?” to a
particular type or a super type of it.
• To create/declare a lower-bounded
wildcard, you just need to specify the
super keyword after the “?” followed by the
class name.
• Example: <? super A>
Unbounded wildcards
• This wildcard type is specified using the
wildcard character (?)
• These are useful in the following cases –
➢ When writing a method that can be
employed using functionality provided in
Object class.
➢ When the code is using methods in the
generic class that doesn’t depend on the
type parameter
Bounded Types
// Stats attempts (unsuccessfully) to
// create a generic class that can compute
// the average of an array of numbers of
// any given type.
//
// The class contains an error!
class Stats<T> {
T[] nums; // nums is an array of type T
// Pass the constructor a reference to
// an array of type T.
Stats(T[] o) {
nums = o;
}
Bounded Types
// Return type double in all cases.
double average() {
double sum = 0.0;
for(int i=0; i < nums.length; i++)
sum += nums[i].doubleValue(); // Error!!!
return sum / nums.length;
}
}
• class Gen<T extends MyClass & MyInterface> { // ...
Using Wildcard Arguments
Integer inums[] = { 1, 2, 3, 4, 5 };
Double dnums[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
Stats<Integer> iob = new Stats<Integer>(inums);
Stats<Double> dob = new Stats<Double>(dnums);
if(iob.sameAvg(dob))
System.out.println("Averages are the same.");
else
System.out.println("Averages differ.");
Using Wildcard Arguments
// This won't work!
// Determine if two averages are the same.
boolean sameAvg(Stats<T> ob) {
if(average() == ob.average())
return true;
return false;
}
Using Wildcard Arguments
// Determine if two averages are the same.
// Notice the use of the wildcard.
boolean sameAvg(Stats<?> ob) {
if(average() == ob.average())
return true;
return false;
}
Creating a Generic Method
// Demonstrate a simple generic method.
class GenMethDemo {
// Determine if an object is in an array.
static <T extends Comparable<T>, V extends T>
boolean isIn(T x, V[] y) {
for(int i=0; i < y.length; i++)
if(x.equals(y[i])) return true;
return false;
}
Creating a Generic Method
public static void main(String args[]) {
// Use isIn() on Integers.
Integer nums[] = { 1, 2, 3, 4, 5 };
if(isIn(2, nums))
System.out.println("2 is in nums");
if(!isIn(7, nums))
System.out.println("7 is not in nums");
System.out.println();
Creating a Generic Method
// Use isIn() on Strings.
String strs[] = { "one", "two", "three", "four", "five" };
if(isIn("two", strs))
System.out.println("two is in strs");
if(!isIn("seven", strs))
System.out.println("seven is not in strs");
// Oops! Won't compile! Types must be compatible.
// if(isIn("two", nums))
// System.out.println("two is in strs");
}
}
Lambda Expressions
• A lambda expression is, essentially, an
anonymous (that is, unnamed) method
• Used to implement a method defined by a
functional interface
• A functional interface is an interface that
contains one and only one abstract method
• A functional interface defines the target type
of a lambda expression
Lambda Expressions
• lambda expression introduces a new syntax element
and operator into the Java language
• new operator, sometimes referred to as the lambda
operator or the arrow operator, is −>
• −> can be verbalized as “becomes” or “goes to.”
• divides a lambda expression into two parts.
- The left side specifies any parameters required by the
lambda expression. (If no parameters are needed, an
empty parameter list is used.)
- On the right side is the lambda body, which specifies
the actions of the lambda expression.
Lambda Expressions
• Java defines two types of lambda bodies
1) a single expression
2) a block of code
• Ex: A simplest type of lambda expression
evaluates to a constant value and is shown
here:
() -> 123.45
• Similar to the following method
Public double myMeth() { return 123.45; }
Lambda Expressions
• () -> Math.random() * 100
• When a lambda expression requires a
parameter, it is specified in the parameter list
on the left side of the lambda operator. Here
is a simple example:
(n) -> (n % 2)==0
Functional Interface
• An interface with only one abstract method
• Example:
interface MyNumber
{
double getValue();
}
• A Lambda Expression is not executed on its own
• A Lambda Expression can be specified only in a context in
which a target type is defined
• Example:
// Create a reference to a MyNumber instance.
MyNumber myNum;
// Use a lambda in an assignment context.
myNum = () -> 123.45;
Lambdas as Objects
• A Java lambda expression is essentially an object
• Assigning to a variable is possible
• Ex:
public interface MyComparator { public boolean
compare(int a1, int a2);
}
MyComparator myComparator = (a1, a2) -> return
a1 > a2;
boolean result = myComparator.compare(2, 5);