4. HOW GOOD YOU ARE AT
GENERICS?
<R> Strudel<R> loop(Function<? super T,? extends R> mapper)<R> Stream<R> map(Function<? super T,? extends R> mapper)
5. A generic type is a generic class or interface that
is parameterized over types.
Code that uses generics has many benefits over
non-generic code:
Stronger type checks at compile time.
Elimination of casts.
Enabling programmers to implement
generic algorithms.
6. public class Box {
private Object object;
public void set(Object o){
this.object = o;
}
public Object get() {
return object;
}
}
public class Box<T> {
private T t;
public void set(T t)
{ this.t = t; }
public T get()
{ return t; }
}
As you can see, all occurrences of Object are replaced by T. A type
variable can be any non-primitive type you specify: any class type,
any interface type, any array type, or even another type variable.
Simple Example
7. public class Test {
public static void main(String[] args) {
BoxPrinter value1 = new BoxPrinter(new Integer(10));
System.out.println(value1);
Integer intValue1 = (Integer) value1.getValue();
BoxPrinter value2 = new BoxPrinter("Hello world");
System.out.println(value2);
// Ooops ...
Integer intValue2 = (Integer) value2.getValue();
}
}
class BoxPrinter {
private Object val;
public BoxPrinter(Object arg) {
val = arg;
}
public String toString() {
return "{" + val + "}";
}
public Object getValue() {
return val;
}
}
8. public class Test {
public static void main(String[] args) {
BoxPrinter<Integer> value1 = new BoxPrinter<Integer>(new Integer(10));
System.out.println(value1);
Integer intValue1 = value1.getValue();
BoxPrinter<String> value2 = new BoxPrinter<String>("Hello world");
System.out.println(value2);
// Compile error
Integer intValue2 = value2.getValue();
}
}
class BoxPrinter<T> {
private T val;
public BoxPrinter(T arg) {
val = arg;
}
public String toString() {
return "{" + val + "}";
}
public T getValue() {
return val;
}
}
9. Naming Conventions
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
10. Integer i = 127;
Class<Integer> c = i.getClass(); //compile error
11. Generic Methods
Generic methods are methods that introduce their own type parameters. This
is similar to declaring a generic type, but 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.
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
12. GENERIC GENERAL RESTRICTIONS
• Cannot Instantiate Generic Types with Primitive Types
• Cannot Create Instances of Type Parameters
• Cannot Declare Static Fields Whose Types are Type
Parameters
• Cannot Use Casts or instanceof With Parameterized
Types
• Cannot Create Arrays of Parameterized Types
• Cannot Create, Catch, or Throw Objects of Parameterized
Types
• Cannot Overload a Method Where the Formal Parameter
Types of Each Overload Erase to the Same Raw Type
13. Cannot Create Instances of Type Parameters
You cannot create an instance of a type parameter. For example, the
following code causes a compile-time error:
But, You can always use Reflection API
public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error
list.add(elem);
}
public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.newInstance(); // OK
list.add(elem);
}
14. Cannot Use Casts or instanceof with Parameterized Types
Because the Java compiler erases all type parameters in generic code, you
cannot verify which parameterized type for a generic type is being used at
runtime:
Cannot Create Arrays of Parameterized Types
You cannot create arrays of parameterized types. For example, the following
code does not compile:
public static <E> void doSmth(List<E> list) {
if (list instanceof ArrayList<Integer>) { // compile-time
error
// some logic
}
}
List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile-
time error
15. Cannot Create, Catch, or Throw Objects of Parameterized Types
A generic class cannot extend the Throwable class directly or indirectly.
// Extends Throwable indirectly
// Extends Throwable directly
A method cannot catch an instance of a type parameter:
You can, however, use a type parameter in a throws clause:
class MathException<T> extends Exception // compile-time error
class QueueFullException<T> extends Throwable // compile-time error
public static <T extends Exception, J> void execute(List<J> jobs) {
try {
for (J job : jobs);
} catch (T e) { // compile-time error
}
}
class Parser<T extends Exception> {
public void parse(File file) throws T { // OK
}
16. public class Quiz5<T> {
public List<Integer> numbers() {
return Arrays.asList(1,2);
}
public static void main(String[] args) {
Quiz5 quiz = new Quiz5();
for (Integer i: quiz.numbers()) {
System.out.println(i);
}
}
}
// wtf?! this code is ok
// ClassCastException
// Compile Error
// NPE
//error here
incompatible types
17. TYPE
Generics were introduced to the Java language to provide
tighter type checks at compile time and to support generic
programming.
To implement generics, the Java compiler applies type
erasure.
18. public class Person implements Comparable<Person> {
private String name;
@Override
public int compareTo(Person o) {
return name.compareTo(o.name);
}
public int compareTo(Object o) {
return toString().compareTo(o.toString());
}
}
//compile error
// both methods have same erasure
ERASURE
19. class Box<T> {
private T value;
public Box (T t) {
this.value = t;
}
public T get() {
return value;
}
}
Box<Integer> box = new Box<>(10);
Integer i = box.get();
Box box = new Box (10);
Integer i = (Integer) box.get();
class Box {
private Object value;
public Box (Object t) {
this.value = t;
}
public Object get() {
return value;
}
}
//java compiles//we write
20. Bridge Methods
public class Person implements Comparable<Person> {
private String name;
@Override
public int compareTo(Person o) {
return name.compareTo(o.name);
}
public static void main(String[] args) {
Stream.of(Person.class.getDeclaredMethods()).
forEach(System.out::println);
}
}
public int Quiz4.Person.compareTo(java.lang.Object)
public int Quiz4.Person.compareTo(Quiz4.Person)
//Sout
//wtf? o.O
21. public interface Comparable<T> {
int CompareTo (T t)
}
public interface Comparable {
int CompareTo (Object o)
}
public class Person implements Comparable<Person> {
@Override
public int compareTo(Person o) {
return 0;
}
}
//isSynthetic()
public int compareTo(Object o) {
return compareTo((Person) o);
}
22. ArrayList - sometimes things are different from what you see
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
. . .
private E[] elementData;
private int DEFAULT_CAPACITY = 10;
. . .
public ArrayList() {
elementData = new E[DEFAULT_CAPACITY];
}
. . .
}
Aww, you fool! It’s not
going to work!
Aww, you fool! It’s not
going to work!
Type parameter «E» cannot
be instantiated directly
23. public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private E[] elementData;
private int DEFAULT_CAPACITY = 10;
public ArrayList() {
elementData = (E[]) new Object[DEFAULT_CAPACITY];
}
. . .
}
As I said in «Effective
Java» - casts are
good.
Well done, my boy!
As I said in «Effective
Java» - casts are
good.
Well done, my boy!
24. Bounds || Restrictions
public class Box <T> {
private T t;
public <U extends Number> void inspect(U u){
System.out.println("T: " +
t.getClass().getName());
System.out.println("U: " +
u.getClass().getName());
}
public static void main(String[] args) {
Box<Integer> integerBox = new
Box<Integer>();
integerBox.set(new Integer(10));
integerBox.inspect("some text");
// error: this is still String!
}
}
class NaturalNumber<T extends Integer> {
private T n;
public NaturalNumber(T n) {
this.n = n;
}
public boolean isEven() {
return n.intValue() % 2 == 0;
}
//The isEven method invokes
//the intValue method defined in
//the Integer class through n.
}
class D <T extends A & B & C> // we can do multiple bounds, BUT …class D <T extends A & B & C> // we can do multiple bounds, BUT …
25. Type Inference
Type inference is a Java compiler's ability to look at each
method invocation and corresponding declaration to
determine the type argument (or arguments) that make the
invocation applicable.
static <T> T pick(T a1, T a2) { return a2; }
Serializable s = pick("d", new ArrayList<String>());
26. Target Types
The Java compiler takes advantage of target typing to infer the
type parameters of a generic method invocation. The target
type of an expression is the data type that the Java compiler
expects depending on where the expression appears.
static <T> List<T> emptyList();
processStringList(Collections.emptyList());processStringList(Collections.emptyList());
void processStringList(List<String> stringList)
{
/* some logic */
}
List<Object> cannot be
converted to List<String>
ClassCastException
Incompatible types
No errors or exceptions//JDK7
29. Upper Bounded WildCards
To write the method that works on lists of Number and the subtypes of Number,
such as Integer, Double, and Float, you would specify List<? extends Number>.
public static void process(List<?
extends Foo> list) { }
public static void process(List<? extends Foo>
list) {
for (Foo elem : list) {
// ...
}
}
public static double sumOfList(List<?
extends Number> list) {
double s = 0.0;
for (Number n : list)
s += n.doubleValue();
return s;
}
List<Integer> li = Arrays.asList(1, 2, 3);
System.out.println("sum = " + sumOfList(li)); //sum = 6.0
List<Double> ld = Arrays.asList(1.2, 2.3, 3.5);
System.out.println("sum = " + sumOfList(ld)); //sum = 7.0
30. Story about no one, experimental
class Foo<T extends Cloneable> {
public void doSomething(T param) {
T copy = (T) param.clone();
}
}
3. this code is perfect,
don’t talk shit
2. incompatible types
1. ClassCastException
4. none above
31. Unbounded Wildcard
The goal of printList is to print a list of any type, but it fails to achieve that goal — it prints only a list of
Object instances; it cannot print List<Integer>, List<String>, List<Double>, and so on, because they are
not subtypes of List<Object>. To write a generic printList method, use List<?>:
Because for any concrete type A, List<A> is a subtype of List<?>, you can use printList to print a list of
any type:
public static void printList(List<Object> list) {
for (Object elem : list)
System.out.println(elem + " ");
System.out.println();
}
public static void printList(List<?> list) {
for (Object elem: list)
System.out.print(elem + " ");
System.out.println();
}
List<Integer> li = Arrays.asList(1, 2, 3);
List<String> ls = Arrays.asList("one", "two", "three");
printList(li);
printList(ls);
32. Lower Bounded Wildcards
You can specify an upper bound for a wildcard, or
you can specify a lower bound, but you cannot
specify both.
<? super X>
As for key word <? extends> You can use <? super>
to specify any base class or interface of X, and X itself
List<? super Integer> list
33. List<? extends Number> numbers = new ArrayList<>();
List<? super Number> numbers = new ArrayList<>();
What we can add to the following
collections via numbers.add() ?
Integer, Double, Number, Long
Object, Number
List<?> list = new ArrayList<>();
anything?
null
null
all that ? extend Number
34. List <? extends Number> list = new ArrayList<>();
list.add(); <- null
List <? extends Number> list = …
list = new ArrayList<Number>;
list = new ArrayList<Integer>;
list = new ArrayList<Long>;
//what compiler sees
//what possibly can come
35. List <? super Number> list = new ArrayList<>();
list.add(); <- all that ? extends Number
List <? super Number> list = …
//what compiler sees
list = ArrayList<Object>();
list = ArrayList<Number>();
//what possibly can come
36. public class MindBlown <T extends MindBlown<T>>
WTF is it? An infinite recursion? How this gonna work?
public class Enum <E extends Enum<E>>
WHY?
1. The type parameter E is used in various methods of Enum, such as compareTo()
or getDeclaringClass()
2. Classes that are type arguments to Enum must themselves be subtypes of Enum,
so you can't declare a class X to extend Enum<Integer>
3. Any class that extends Enum must pass itself as the type parameter. You cannot
declare X to extend Enum<Y>, even if Y extends Enum.
49. Set<Number> set = new TreeSet<>();
set.add(1);
set.add(1L);
set.add(1.00);
System.out.println(set.size());
A. 3 B. Compile error
C. 2 D. Runtime error
57. public class Compressor<T> {
String compress(Collection<?> obj) {
String s = "";
for (Object o : obj)
s += obj.toString();
return s;
}
int compress(List<Integer> list) {
int result = 0;
for (int i: list)
result+=i;
return result;
}
public static void main(String[] args) {
List<String> list = Arrays.asList("1","2","3");
System.out.println(new Compressor().compress(list));
}
}
1. Compile error
2. Runtime error
3. 6
4. 123
// classCastException
58. PECS (Producer - extends, Consumer - super)
If a parametrized type represents a T
producer -
use <? extends T>;
If a parametrized type represents a T
consumer -
use <? super T>;
Joshua Bloch
public static <T> T max(Collection<? extends T> coll,
Comparator<? super T> comp);
59. Integer i = 127;
Class<Integer> c = i.getClass(); //compile error
Why this isn’t working?class Object {
Class<?> getClass();
}
class Number {
Class<Number>
getClass();
}
class Integer {
Class<Integer>
getClass();
60.
61. 1, 2, 3, 1440988108
1, 2, 3, 23 nov 2016 19:56:00:00:00
ClassCastException
Compile error
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(2L);
list.add(3L);
Date now = new Date();
list.add(now);
for (def node: list) {
System.out.println(node);
}