Generics and Collections
Generics and Collections
} }
} }
Redundancy!
class Print{ class Print{
String o; Float o;
Print(String o){ Print(Float o){
this.o = o; this.o = o;
System.out.println(o); System.out.println(o);
} }
} }
Solution: Use Generics!
class Print<T>{
T o;
Print(T o){
this.o = o;
System.out.println(o);
}
}
Why Use Generics?
●
Generics enable types (classes and
interfaces) to be parameters when defining
classes, interfaces and methods.
– type parameters provide a way to re-use the
same code with different types of inputs.
Benefits of code that uses generics
● Stronger type checks at compile time.
● Elimination of casts.
– without generics requires casting:
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);
– with generics, the code does not require casting:
List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast
●
Enabling programmers to implement generic algorithms.
Generic Types
●
A generic type is a generic class or interface that is parameterized
over types.
●
a non-generic Box class that operates on objects of any type:
public class Box {
private Object object;
public void set(Object object) {
this.object = object;
}
public Object get() { return object; }
}
Generic Types
●
Since its methods accept or return an Object,
– you are free to pass in whatever you want,
– provided that it is not one of the primitive types.
●
There is no way to verify, at compile time, how the
class is used.
– One part of the code may place an Integer in the box and
expect to get Integers out of it,
– while another part of the code may mistakenly pass in a
String, resulting in a runtime error.
Generic Types
●
A generic class is defined with the following format:
class name<T1, T2, ... , Tn> {
/* ... */
}
– The type parameter section, delimited by angle brackets <>
– It specifies the type parameters (also called type variables)
T1, T2, ..., and Tn.
Generic Types
●
A Generic Version of the Box Class
public class Box<T> {
// T stands for "Type"
private T t;
Pair<String, String> p2 =
new OrderedPair<String, String>("hello", "world");
OrderedPair<String, Integer> p1 =
new OrderedPair<>("Even", 8);
OrderedPair<String, String> p2 =
new OrderedPair<>("hello", "world");
– Java compiler can infer the K and V types from the declaration
OrderedPair<String, Integer>
Shortening
●
You can also substitute a type parameter with a parameterized
type.
OrderedPair<String, Box<Integer>> p = new
OrderedPair<>("primes", new Box<Integer>(...));
Raw Types
●
A raw type is the name of a generic class or interface without any type
arguments.
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
●
To create a parameterized type of Box<T>, you supply an actual type
argument for the formal type parameter T:
Box<Integer> intBox = new Box<>();
●
If the actual type argument is omitted, you create a raw type of Box<T>:
Box rawBox = new Box();
Raw Types
●
Therefore, Box is the raw type of the generic type Box<T>.
– However, a non-generic class or interface type is not a raw type.
●
Raw types show up in legacy code because lots of API classes
(such as the Collections classes) were not generic prior to JDK
5.0.
– When using raw types, you essentially get pre-generics behavior — a
Box gives you Objects.
– For backward compatibility, assigning a parameterized type to its raw
type is allowed
Raw Types
Box<String> stringBox = new Box<>();
Box rawBox = stringBox; // OK
●
But if you assign a raw type to a parameterized
type, you get a warning:
Raw Types
Box rawBox = new Box(); // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox;//warning:unchecked conversion
●
You also get a warning if you use a raw type to invoke generic methods defined in
the corresponding generic type:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
●
The warning shows that raw types bypass generic type checks, deferring the
catch of unsafe code to runtime. Therefore, you should avoid using raw types.
Generic Methods
●
are methods that introduce their own type parameters.
– the type parameter's scope is limited to the method where it is
declared.
– Static and non-static generic methods are allowed, as well as generic
class constructors.
●
The syntax includes a list of type parameters, inside angle
brackets, which appears before the method's return type.
public static <K, V> boolean compare(
Pair<K, V> p1,
Pair<K, V> p2)
Generic Methods
● The Util class includes a generic method, compare, which compares two Pair
objects:
class InvalidUse {
void use(List<> data) {} // DOES NOT COMPILE
}
Adding Data
● The add() method inserts a new element into the Collection and returns whether it
was successful.
public boolean add(E element)
3: Collection<String> list = new ArrayList<>();
4: System.out.println(list.add("Sparrow")); // true
5: System.out.println(list.add("Sparrow")); // true
6:
7: Collection<String> set = new HashSet<>();
8: System.out.println(set.add("Sparrow")); // true
9: System.out.println(set.add("Sparrow")); // false
//A Set does not allow duplicates.
Removing Data
● The remove() method removes a single matching value in the Collection and
returns whether it was successful.
public boolean remove(Object object)
//return value tells us whether a match was removed