/
Effective Java: 3 rd  Edition Effective Java: 3 rd  Edition

Effective Java: 3 rd Edition - PowerPoint Presentation

sylvia
sylvia . @sylvia
Follow
342 views
Uploaded On 2022-06-28

Effective Java: 3 rd Edition - PPT Presentation

Generics Last Updated Fall 2019 Agenda Material From Joshua Bloch Effective Java Programming Language Guide Cover Items 2631 33 Generics Chapter Bottom Line Generics are safer than raw types ID: 926633

type list set public list type public set result string object static size item class return generics collection raw

Share:

Link:

Embed:

Download Presentation from below link

Download Presentation The PPT/PDF document "Effective Java: 3 rd Edition" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.


Presentation Transcript

Slide1

Effective Java: 3rd Edition Generics

Last Updated: Fall 2019

Slide2

AgendaMaterial From Joshua Bloch

Effective Java: Programming Language Guide

Cover Items 26-31, 33

“Generics” Chapter

Bottom Line:

Generics are safer, than raw types

But generics are also more complex

Raw types are allowed for backwards compatibility

Slide3

Item 26: Don’t Use Raw Types in New CodeA class (interface) with one or more type parameters is a

generic

class (interface)

Examples:

List

is a

raw

type

List<E>

is a

generic

interface

List<String>

is a parameterized type

String

is the actual type parameter corresponding to

E

Slide4

Example: Replacing raw types

// Now a raw collection type –

don’t do this

private final Collection stamps = …; // Contains only Stamps

// Erroneous insertion of coin into stamp collection

stamps.add(new Coin(…)); // Oops! We’re set up for ClassCastException later

// Parameterized collection type - typesafe

private final Collection<Stamp> stamps = …;

stamps.add(new Coin(…)); // result is instead a

compile

time error, which is

good

// Now a raw iterator type –

don’t do this!

for (Iterator I = stamps.iterator(); i.hasNext(); ) {

Stamp s = (Stamp) i.next(); // Throws ClassCastException

…// Do something with the stamp

}

// for-each loop over parameterized collection – typesafe

for (Stamp s: stamps) { // No (explicit) cast

…// Do something with the stamp

}

Slide5

Example: Mixing generic and raw types

// Uses raw type (List) –

fails at runtime

public static void main(String[] args) {

List<String> strings = new ArrayList<String>();

unsafeAdd(strings, new Integer(42));

String s = strings.get(0); //

Exception from compiler generated cast

}

// note use of raw types

private static void unsafeAdd(List list, Object o) {

list.add(o);

}

// There is a compile time warning:

Test.java:10: warning: unchecked call to add(E) in raw type List

list.add(o);

^

// If we ignore the warning, and run the program, we get a ClassCastException

// where the compiler inserted the cast

// If we try the following, it won’t compile (see Item 25)

private static void unsafeAdd(

List<Object> list

, Object o) { list.add(o);}

Slide6

Example: Using Wildcards

//

Use of raw type for unknown element type – don’t do this!

static int numElementsInCommonSet (Set s1, Set s2) {

int result = 0;

for (Object o1: s1)

{ if (s2.contains(o1)) result ++; }

return result;

}

//

Unbounded wildcard type – typesafe and flexible

static int numElementsInCommonSet (Set<?> s1, Set<?> s2) {

int result = 0;

for (Object o1: s1)

{ if (s2.contains(o1)) result ++; }

return result;

}

// We’ll revisit this type of example in Item 27

Slide7

Example: Using Wildcards

// Do the question marks really buy you anything?

// Answer: Wildcard is typesafe,

// because you can’t add *anything* (except null) to Collection<?>

// Two exceptions: Raw types ok in

Class Literals: List.class, not List<String>.class

instanceof operator

if (o instanceof Set) { // raw type ok

Set<?> m = (Set<?>) o; // Wildcard type

// Why the exceptions? Compatibility with old Java

Slide8

Terminology

Term Example Item

Parameterized type List<String> Item 23

Actual type parameter String Item 23

Generic type List<E> Items 23, 26

Formal type parameter E Item 23

Unbounded wildcard type List<?> Item 23

Raw type List Item 23

Bounded type parameter <E extends Number> Item 26

Recursive type bound <T extends Comparable<T>> Item 27

Bounded wildcard type List<? extends Number> Item 28

Generic method static <E> List<E> asList(E[] a) Item 27

Type token String.class Item 29

Slide9

Item 27: Eliminate Unchecked WarningsGenerics result in many compiler warnings

Eliminate them

As a last resort, suppress the warnings

Do so as at local a level as possible

Options are class down to local declaration

Use the

@SuppressWarnings

annotation

Some are easy:

Set<Lark> exaltation = new HashSet(); // warning

Set<Lark> exaltation = new HashSet <Lark>(); // no warning

Slide10

Example: Suppressing Warnings

public <T> T[] toArray (T[] a) {

if (a.length < size)

return (T[]) Arrays.copyOf(elements, size, a.getClass());

System.arraycopy(elements, 0, a, 0, size);

if (a.length > size) a[size] = null;

return a; }

The compiler generates a warning:

ArrayList.java:305: warning [unchecked] unchecked cast

found : Object[], required T[]

return (T[]) Arrays.copyOf(elements, size, a.getClass());

Suppressing the warning:

if (a.length < size) {

// This cast is correct because the array we’re creating

// is of the same type as the one passed in, which is T[]

@SuppressWarnings(“unchecked”)

T[] result = (T[]) Arrays.copyOf(elements, size, a.getClass());

return result; }

Slide11

Item 28: Prefer Lists to ArraysLists play well with generics

Generic array creation not typesafe (hence illegal)

No new List<E>[], new List<String>[] , or new E[]

Arrays are covariant; generics are invariant

If Sub is a subtype of Super

Then Sub[] is a subtype of Super[]

But List<Sub> is

not

a subtype of List<Super>

Arrays are reified; generics are erased

Generics are compile time only

Slide12

Example: Covariance vs. Invariance

// Fails at runtime

Object[] objectArray = new Long[1];

objectArray[0] = “I don’t fit in!”; // Throws ArrayStoreException

// Won’t compile

List<Object> o1 = new ArrayList<Long>();

o1.add(“I don’t fit in!”); // Incompatible types

Not compiling is better than a runtime exception.

This is basically an argument for why invariance is preferable to covariance for generics.

Later, we’ll see how to relax this.

Slide13

Example: Illustrating type (non) safety

// Why generic array creation is illegal – won’t compile

1) List<String>[] stringLists = new List<String>[1]; // won’t compile

2) List<Integer> intList = Arrays.asList(42);

3) Object[] objects = stringLists;

4) objects[0] = intList;

5) String s = stringLists[0].get(0); // compiler generated cast to String

Suppose 1) compiled (it won’t)

2) Creates and initializes a List<Integer> with one element

3) Stores the List<String> object into an Object array variable,

note, this is legal because arrays are covariant

4) Stores the List<Integer> into the sole element of the Object array

this succeeds because generics are implemented by erasure.

The runtime type is simply List[], so there is no exception

5) Now, we’ve stored a List<Integer> instance into an array that is declared

to hold only List<String> instances. So, we get a ClassCastException

Slide14

Example: Chooser class

//

Chooser – a class badly in need of generics

p

ublic class Chooser {

private final Object[]

choiceArray

;

public Chooser(Collection choices) {

choiceArray

=

choices.toArray

();

}

public Object choose() {

Random

rnd

=

ThreadLocalRandom.current

();

return

choiceArrary

[

rnd.nextInt

(

choiceArray.length

)];

}

}

Flaw: client must always cast return value; hence no type safety

Flaw: what if collection is empty?

Slide15

Example: First cut at fixing

//

A first cut at making Chooser generic – won’t compile

p

ublic class Chooser

<T>

{

private final

T

[]

choiceArray

;

public Chooser(Collection

<T>

choices) {

choiceArray

=

choices.toArray

();

// could fix with

choiceArray

=

(T[])

choices.toArray

();

}

// choose method unchanged

}

Compiler objects to “

choiceArray

=

choices.toArray

()”;

Fix still yields a warning

Slide16

Example: prefer lists to arrays

//

List-based chooser -

typesafe

// abstract invariant – Chooser objects are never empty

p

ublic

class Chooser<T> {

private final

List<T>

choiceList

;

// reject empty collections -

public Chooser(Collection choices) {

if (

choices.size

() == 0) throw new IAE(…);

choiceList

=

new

ArrayList

(choices);

}

public

T

choose() {

Random

rnd

=

ThreadLocalRandom.current

();

return

choiceList.get

(

rnd.nextInt

(

choiceList.size

()));

}

}

Slide17

Item 29: Favor Generic TypesParameterize collection declarations

Use the generic types

Implementer has to work harder

But clients have type safety

Stack example: How to support this?

public static void main (String[] args) {

Stack<String> stack = new Stack<String>();

for (String arg: args) { stack.push(arg);}

while (!stack.isEmpty()) { …stack.pop()…}

}

Slide18

Example: Converting collection to generics

public class Stack {

// Original Version – no generics

private

Object

[] elements;

private int size = 0;

private static final int CAP = 16;

public Stack() { elements = new

Object

[CAP];}

public void push(

Object

e ) {

ensureCapacity();

elements [size++] = e;

}

public

Object

pop() {

if (size == 0) { throw new ISE(…); }

Object

result = elements [--size];

elements[size] = null;

return result;

}

// remainder of Stack omitted – See Bloch

Slide19

Example: Converting collection to generics

public class Stack

<E>

{

// First cut at generics – won’t work

private

E

[] elements; // Alternate 2: Leave as Object

private int size = 0;

private static final int CAP = 16;

public Stack() { elements = new

E

[CAP];} // error; generic array creation

// Alternate 1: = new (E[]) Object [CAP];} // warning

// @SuppressWarning(“unchecked”)

//public Stack() { elements = new (E[]) Object [CAP];} // warning suppressed

public void push(

E

e ) {

ensureCapacity();

elements [size++] = e;

}

public

E

pop() {

if (size == 0) { throw new ISE(…); }

E

result = elements [--size]; // Error for Alternate 2; also cast and suppress warning

elements[size] = null;

return result;

}

Slide20

Item 30: Favor Generic MethodsJust as classes benefit from generics

So do methods

Writing generic methods is similar to writing generic types

Slide21

Example: Generic method

// Uses raw types – unacceptable! (Item 23)

public static Set union (Set s1, Set s2) {

Set result = new HashSet(s1); // Generates a warning

result.addAll(s2); // Generates a warning

return result;

}

// Generic method

public static <E> Set <E> union (Set <E> s1, Set <E> s2) {

Set <E> result = new HashSet <E> (s1);

result.addAll(s2);

return result;

}

// The first <E> is the type parameter list

// Example from the java.util.Collection

// The generics can get a bit redundant…

Map <String, List<String>> anagrams = new HashMap<String, List<String>>();

Slide22

Example: Recursive Type Bound (1)

/*

*

Returns the maximum value in a

list

* what must be true of type T?

* what exceptions are thrown and when?

*/

public static

<?????????> T

max (List <T> list

)

This is a great example because it is *so* simple.

We’re just finding the max value!

Yet the corner cases are tricky.

It’s one of the rare places in

Effective Java

where Bloch errs.

Slide23

Example: Recursive Type Bound (2)

/*

* what must be true of type T?

*/

public static

<?????????> T

max (List <T> list)

Slide24

Example: Recursive Type Bound (3)

/*

* what exceptions are thrown and when?

*/

public static

<T extends Comparable<T>> T

max (List <T> list

)

@throws NPE if

@throws NSEE (or IAE) if

@throws CCE if

Slide25

Example: Recursive Type Bound (4)

/*

* what exceptions are thrown and when?

*/

public static

<T extends Comparable<T>> T

max (List <T> list

)

@throws NPE if list is null or contains null values

@throws NSEE (or IAE) if list is empty

@throws CCE if list contains mutually incomparable objects

Slide26

Example: Recursive Type Bound (5)

// Returns the maximum value in a list – uses recursive type bound

public static <T extends Comparable<T>> T max (List <T> list) {

Iterator <T> i =

list.iterator

();

T result =

i.next

();

while (

i.hasNext

()) {

T

t

=

i.next

(); // Note: no need for a cast

if (

t.compareTo

(result) > 0)

result = t;

}

return result;

}

// Bloch’s solution: How does he do on the contract?

Slide27

Example: Recursive Type Bound (6)

// Returns the maximum value in a list – uses recursive type bound

public static <T extends Comparable<T>> T max (List <T> list) {

if (

list.size

() == 0) throw new NSEE(…); // or IAE

T result =

list.get

(0);

for

(

T

t

: list

) { // simpler code, slightly less efficient, but correct!

if (

t.compareTo

(result) > 0

)

result = t;

}

return result;

}

// One way to correct Bloch’s solution

Slide28

Item 31: Use bounded wildcards to increase API Flexibility

public class Stack

<E>

{

// First cut at generics – won’t work

public Stack()

public void push(

E

e )

public

E

pop()

public boolean isEmpty()

}

//

pushAll method without a wildcard type – deficient!

public void pushAll(

Iterable<E>

src) {

for (E e : src) { push(e); }

}

//

wildcard type for parameter that serves as an E producer

public void pushAll(

Iterable<? extends E>

src) {

for (E e : src) { push(e); }

}

//

wildcard type for parameter that serves as an E consumer

public void popAll (

Collection<? super E>

dst) {

while (!isEmpty()) { dst.add(pop()); }

}

Slide29

The PECS mnemonic

//

PECS – producer extends, consumer super

// Recall earlier example

public static <E> Set <E> union (Set <E> s1, Set <E> s2)

// Are parameters consumers or producers? (

Producers

, so, extend)

public static <E> Set <E> union (Set <? extends E> s1, Set <? extends E> s2)

// Note that return type should still be Set<E>, not Set <? extends E>

// otherwise, clients will have to use wildcards…

Set<Integer> integers = …

Set<Double> doublse = …

Set<Number> numbers = union ( integers, doubles); // compiler error

Set<Number> numbers = union

.<Number>

( integers, doubles); // type parameter works

// max example

public static <T extends Comparable<T>> T max (List <T> list ) // original

public static <T extends Comparable<? super T>> T max (List<? extends T> list) // PECS

Slide30

Item 33: Consider typesafe heterogeneous Containers

//

Typesafe heterogeneous container pattern – implementation

public class Favorites

private

Map<Class<?>, Object> favorites

= new HashMap(<Class<?>, Object>();

public <T> void putFavorite(Class<T> type, T instance) {

if (type == null) { throw new NPE… }

favorites.put (type, instance);

}

public <T> T getFavorite(Class<T> type) {

return

type.cast(favorites.get(type));

}

// Fairly subtle stuff…