More Related Content Similar to Java Generics: a deep dive (10) Java Generics: a deep dive1. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Java Generics
History
& Theory
Creating a
Odds & Sods
Generic Class
Java Generics:
a Deep Dive
Creating a Creating a
Generic Generic Method
Framework
Generics in Recursive
Frameworks Generic Types
Bryan Basham
Software Alchemy
basham47@gmail.com
http://www.linkedin.com/in/SoftwareAlchemist
Bryan Basham – Java Generics: a Deep Dive Slide 1
2. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
History & Theory
Erasure Wildcards & PECS
History
Mixing w/
Raw Types
History
& Theory
Creating a
Odds & Sods
Generic Class
Java Generics:
a Deep Dive
Creating a Creating a
Generic Generic Method
Framework
Generics in Recursive
Frameworks Generic Types
Bryan Basham – Java Generics: a Deep Dive Slide 2
3. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Why Are Generics Important?
● The great debate of dynamic vs static
languages
– Dynamic is great for rapid prototyping
– Static is better for serious engineering
– I love both, but...
● This talk is about serious engineering, so...
– Let the compiler catch more potential bugs
– Apply more rigor to your designs
– Add more flexibility to your designs
Bryan Basham – Java Generics: a Deep Dive Slide 3
4. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
History
● Generic types were introduced in J2SE 5.0 in
2004
– Additional type safety
– Reduced the need for casting
● Pre-generics code example:
List v = new ArrayList();
v.add(“test”);
Integer i = (Integer) v.get(0); // Run-time error
● Post-generics:
List<String> v = new ArrayList<String>();
v.add(“test”);
Integer i = v.get(0); // Compile-time error
Bryan Basham – Java Generics: a Deep Dive Slide 4
5. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Theory
● Unlike C++ templates
– Primitives cannot be type parameters
List<int> numbers; // not legal
– Only one generated code file
● Generics are a compile-time feature
– At run-time type variables (eg T) become Object
– This is called erasure
public class LispList<T> { public class LispList {
private T item; private Object item;
private LispList<T> next; private LispList next;
public T first() {...} public Object first() {...}
// etc... // etc...
} }
Bryan Basham – Java Generics: a Deep Dive Slide 5
6. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Terminology
Type Parameter
● Generic type:
public class LispList<T> { ... }
public class Pair<T1, T2> { ... }
Type Argument
● Parameterized type: (required in Java 5 & 6)
LispList<String> list = new LispList<String>("first");
Pair<String,Integer> p1 = new Pair<String,Integer>("random number", 47);
● Type inference in Java 7:
Pair<String,Integer> p1 = new Pair<>("random number", 47);
Map<FrequencyCategory, “the diamond”
Map<RecencyCategory,
EnumMap<RfmAnalysisStatistic, Number>>> rfmContent =
new HashMap<>();
Bryan Basham – Java Generics: a Deep Dive Slide 6
7. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
More Terminology
Wildcard Argument
● Generic method: (unbounded)
public void printPair(Pair<?,?> p) {
System.out.println("(" + p.getFirst() + "," + p.getSecond() + ")");
}
Upper-Bound Wildcard
● Bounded wildcards:
public interface DomainEntityDAO<T extends DomainEntity> {
public long create(T entity);
public T findById(long id);
}
Generic Method Type Parameter Lower-Bound Wildcard
public static <T> void flush(Collection<T> coll, Sink<? super T> sink) {
// flush all elements in the collection to the sink
}
Bryan Basham – Java Generics: a Deep Dive Slide 7
8. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
The PECS Principle
● Producers use extends:
public T something() { /* this method produces a T or subclasses */ }
● Consumers use super:
public void something(T) { /* this method consumes a T or ancestors */ }
● So what? The collection produces elements
to compare to find the max.
// from the java.util.Collections API:
public static <T> T max(Collection<? extends T> collection,
Comparator<? super T> comparator)
The comparator consumes elements
● More explanation: click here while performing the comparison.
Bryan Basham – Java Generics: a Deep Dive Slide 8
9. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Mixing Raw Types with Generics
● A raw type is a use of a generic type without
type arguments: Raw Type
List<String> list1 = new ArrayList();// legal, but with warnings
list1.add("abc");
list1.add(47); // not legal
– Compiler treats this as a list of strings (only); the
type info is on the variable not the RT object
@SuppressWarnings("rawtypes") // use this to suppress warnings
List<?> list3 = new ArrayList();
list3.add("abc"); // not legal
list3.add(47); // not legal
list3.add(null); // null is the only legal value
– Compiler treats this as a list of unknown values
Bryan Basham – Java Generics: a Deep Dive Slide 9
10. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Mixing Raw Types with Generics
● More examples:
List list5 = new ArrayList<String>();
list5.add("abc"); // legal
list5.add(47); // legal, but not type-safe
– Compiler treats this as a list of anything
List list6 = new ArrayList<?>(); // compiler error
– Not legal to use wildcards in instantiation syntax
● Don't mix raw types with generic types
– Unless integrating with legacy APIs
– NEVER use raw types in new code
Bryan Basham – Java Generics: a Deep Dive Slide 10
11. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Creating a Generic Class
Erasure Wildcards & PECS
History
Mixing w/
Raw Types
History
Simple Ex
& Theory
Complex Ex
Creating a
Odds & Sods
Generic Class Multiple Type Params
Other Types
Java Generics:
a Deep Dive
Creating a Creating a
Generic Generic Method
Framework
Generics in Recursive
Frameworks Generic Types
Bryan Basham – Java Generics: a Deep Dive Slide 11
12. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
A Simple Example
● A class with one type parameter:
public class Optional<T> {
private final T item;
public Optional(T item) {
this.item = item;
}
public boolean isPresent() {
return item != null;
}
public T or(T defaultValue) {
return item != null ? item : defaultValue;
}
public T get() {
if (item != null) { return item; }
else { throw new IllegalStateException(); }
}
}
Bryan Basham – Java Generics: a Deep Dive Slide 12
13. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
A Simple Example: Unit Tests
● A class with one type parameter:
@Test
public void test() {
Integer item = null;
Optional<Integer> opt = new Optional<Integer>(item);
assertTrue(!opt.isPresent());
assertEquals(47, opt.or(47).intValue());
try { int value = opt.get(); fail(); }
catch (IllegalStateException e) { /* succeeds */ }
item = 42;
opt = new Optional<Integer>(item);
assertTrue(opt.isPresent());
assertEquals(42, opt.or(47).intValue());
assertEquals(42, opt.get().intValue());
}
● BTW, this is a hack of a real Guava class
Bryan Basham – Java Generics: a Deep Dive Slide 13
14. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Example: Classic link list
● A LISP-like linked list implementation:
public class LispList<T> {
private final T head;
private LispList<T> tail;
public LispList(T head) {
this.head = head;
}
public T first() {
return head;
}
public LispList<T> rest() {
return tail;
}
public LispList<T> addToFront(T item) {
LispList<T> newHead = new LispList<T>(item);
newHead.tail = this;
return newHead;
}
}
Bryan Basham – Java Generics: a Deep Dive Slide 14
15. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Example: Classic link list
● Simple usage test:
@Test
public void testAdd() {
LispList<String> list = new LispList<String>("first");
list = list.addToFront("second");
list = list.addToFront("third");
list = list.addToFront("fourth");
// test the link chain
assertEquals("fourth", list.first()); // car
assertEquals("third", list.rest().first()); // cadr
assertEquals("second", list.rest().rest().first()); // caddr
assertEquals("first", list.rest().rest().rest().first());
}
Bryan Basham – Java Generics: a Deep Dive Slide 15
16. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Example: Classic link list
● Use generic interfaces to extend behavior:
public class LispList<T> implements Iterable<T> {
// skip previous code
@Override
public Iterator<T> iterator() {
return new LispListIterator<T>(this);
}
private static class LispListIterator<T> implements Iterator<T> {
private LispList<T> currentHead;
private LispListIterator(LispList<T> listHead) {
currentHead = listHead;
}
@Override
public boolean hasNext() {
return currentHead != null;
}
@Override
public T next() {
T item = currentHead.head;
currentHead = currentHead.tail;
return item;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}
Bryan Basham – Java Generics: a Deep Dive Slide 16
17. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Example: Classic link list
● Test the iterable behavior:
@Test
public void testAdd() {
LispList<Integer> list = new LispList<Integer>(0);
list.addToEnd(1);
list.addToEnd(2);
list.addToEnd(3); You can use any Iterable as the
// target of a for-each statement.
int count = 0;
for (int value : list) {
assertEquals(count++, value);
}
}
Bryan Basham – Java Generics: a Deep Dive Slide 17
18. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Using Multiple Type Params
● A class with two type parameters:
public class Pair<T1, T2> {
private final T1 first;
private final T2 second;
public Pair(T1 o1, T2 o2) {
this.first = o1;
this.second = o2;
}
public T1 getFirst() {
return first;
}
public T2 getSecond() {
return second;
}
}
Bryan Basham – Java Generics: a Deep Dive Slide 18
19. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Using Multiple Type Args
● Unit test for our Pair class:
@Test
public void test1() {
Pair<String, Long> p1 = new Pair<String, Long>("a test", 47L);
assertEquals("a test", p1.getFirst());
assertEquals(new Long(47), p1.getSecond());
// Java 7
Pair<String, Long> p2 = new Pair<>("life & everything", 42L);
assertEquals("life & everything", p2.getFirst());
assertEquals(new Long(42), p2.getSecond());
}
Bryan Basham – Java Generics: a Deep Dive Slide 19
20. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Generic Interfaces
● A generic function to determine the truth of
some condition:
public interface Predicate<T> {
public boolean apply(T input);
}
private static final Predicate<Integer> IS_EVEN_P = new Predicate<>() {
public boolean apply(Integer input) { return input % 2 == 0; }
};
● A generic function to transform an input from
one value to another:
public interface Function<FROM, TO> {
public TO apply(FROM input);
}
● BTW, these are also part of Guava; one of my favorite Java libraries
Bryan Basham – Java Generics: a Deep Dive Slide 20
21. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Predicate Unit Test
@Test
public void predicateTest() {
List<AppParameter> parameters = new ArrayList<>();
parameters.add(p1 = new AppParameter(PARAM1, VALUE1));
parameters.add(p2 = new AppParameter(PARAM2, VALUE2));
parameters.add(p3 = new AppParameter(PARAM3, VALUE3));
// change a few values
p1.setValue(NEW_VALUE1);
p2.setValue(NEW_VALUE2);
// test the "is dirty" function
Collection<AppParameter> dirtyList =
CollectionUtils.gather(parameters, new Predicate<>() {
@Override
public boolean apply(AppParameter input) {
return input.isDirty();
};
});
assertEquals(2, dirtyList.size());
}
Bryan Basham – Java Generics: a Deep Dive Slide 21
22. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Other Generic Types
● These types can be made generic...
– Classes
– Interfaces
– Inner classes, etc
● These Java types may not be generic:
– Anonymous inner classes
– Exceptions
– Enums
Bryan Basham – Java Generics: a Deep Dive Slide 22
23. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Creating a Generic Method
Erasure Wildcards & PECS
History
Mixing w/
Raw Types
History
Simple Ex
& Theory
Complex Ex
Creating a
Odds & Sods
Generic Class Multiple Type Params
Other Types
Java Generics:
Simple Ex
a Deep Dive
Creating a Creating a
Generic Generic Method Complex Ex
Framework
PECS Reprised
Generics in Recursive
Frameworks Generic Types
Bryan Basham – Java Generics: a Deep Dive Slide 23
24. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Why Generic Methods?
● Generic methods allow you to create
algorithms that apply to a wide variety of types.
● For example, how many sorting algorithms do
you need?
– Sort a list of integers
– Sort a list of dates
– Sort a list of strings
● What do these all have in common?
Bryan Basham – Java Generics: a Deep Dive Slide 24
25. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
A Simple Generic Method
● Gather all items in a collection that satisfy the
given predicate:
public static <T> Collection<T> gather(final Iterable<T> collection,
final Predicate<T> predicate)
{
checkNotNull(collection, "collection must not be null");
checkNotNull(predicate, "predicate must not be null");
Collection<T> result = new ArrayList<T>();
for (T item : collection) {
if (predicate.apply(item)) {
result.add(item);
}
}
return result;
}
Bryan Basham – Java Generics: a Deep Dive Slide 25
26. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
A gather Method Unit Test
@Test
public void testGather() {
// Gather negative numbers
Collection<Integer> test1 =
CollectionUtils.gather(Arrays.asList(TEST_NUMS), IS_NEG);
assertEquals(test1.size(), NEG_NUMBERS_ARRAY.length);
for (Integer n : NEG_NUMBERS_ARRAY) {
assertTrue("elements are correct", test1.contains(n));
}
}
private static final Integer[] TEST_NUMS = {
-42, 42, 0, 13, -47, 42, 42, 47
};
private static final Integer[] NEG_NUMBERS_ARRAY = { -42, -47 };
private static final Predicate<Integer> IS_NEG = new Predicate<>() {
public boolean apply(Integer input) { return input < 0; }
};
Does anyone see the bug in this code?
Bryan Basham – Java Generics: a Deep Dive Slide 26
27. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
A More Complex Example
● A mapping operation:
public static <F, T> Collection<T> map(
final Collection<F> collection,
final Function<F, T> transformer) {
checkNotNull(collection, "collection must not be null");
checkNotNull(transformer, "transformer must not be null");
Collection<T> result = new ArrayList<T>();
for (F item : collection) {
result.add(transformer.apply(item));
}
return result;
}
Bryan Basham – Java Generics: a Deep Dive Slide 27
28. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
A More Complex Example
@Test
public void testMap() {
// Square all of the test numbers
Collection<Integer> test1 =
CollectionUtils.map(TEST_NUMBERS, SQUARE);
assertEquals(test1.size(), TEST_NUMBERS.size());
Iterator<Integer> numbers = TEST_NUMBERS.iterator();
Iterator<Integer> squares = test1.iterator();
while (numbers.hasNext()) {
int n = numbers.next().intValue();
int square = squares.next().intValue();
assertEquals("elements are correct", n * n, square);
}
}
private static final Function<Integer, Integer> SQUARE =
new Function<Integer, Integer>() {
public Integer apply(Integer x) { return x * x; }
};
The compiler requires type arguments for
anonymous inner classes; that was the bug
two slides ago.
Bryan Basham – Java Generics: a Deep Dive Slide 28
29. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
PECS Reprised
● So... what about that sorting problem? Can we
create a single algorithm for all of these (and
more)?
– Sort a list of integers
– Sort a list of dates
– Sort a list of strings
● What do these all have in common?
● How does this relate to the Producer-extends,
Consumer-super principle?
Bryan Basham – Java Generics: a Deep Dive Slide 29
30. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
And now the answer...
● Sorting requires that the objects in the
collection are “comparable” to each other:
public static <T extends Comparable<? super T>> void sort(
List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
● ...of course, this algorithm is kind-of cheating
because it really sorts an array of Objects
and that method uses casts to Comparable.
Bryan Basham – Java Generics: a Deep Dive Slide 30
31. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Recursive Generic Types
Erasure Wildcards
History
Mixing w/
Raw Types
History
Simple Ex
& Theory
Complex Ex
Creating a
Odds & Sods
Generic Class Multiple Type Params
Other Types
Java Generics:
Simple Ex
a Deep Dive
Creating a Creating a
Generic Generic Method Complex Ex
Framework
PECS Reprised
Generics in Recursive
Frameworks Generic Types
Simple Ex
Enums
Class
Bryan Basham – Java Generics: a Deep Dive Slide 31
32. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Recursive Generic Types
● “A recursive generic type is any type that
makes use of a generic type that has a type
argument that refers to the original type.” (me)
● This is not part of the formal definition of Java
generics, but I find the concept useful.
– Because they pop-up every so often
– And cause problems if you don't handle them
correctly
Bryan Basham – Java Generics: a Deep Dive Slide 32
33. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
A Quasi-Recursive Generic
● The Comparable interface forms a quasi-
recursive generic. For example:
public class RevenueBand implements Comparable<RevenueBand> {
private String name;
private int lowerBound;
private int upperBound;
@Override
public int compareTo(RevenueBand that) {
return this.lowerBound – that.lowerBound;
}
}
revBand1 = new RevenueBand("<$1M", 0, 1_000_000);
revBand2 = new RevenueBand("$1M - $10M", 1_000_000, 10_000_000);
revBand3 = new RevenueBand("$10M - $50M", 10_000_000, 50_000_000);
assertTrue(revBand1.compareTo(revBand2) < 0);
Bryan Basham – Java Generics: a Deep Dive Slide 33
34. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Enums
● Java enums are special types that always
extend Enum, which is defined as:
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
...
}
● This recursive definition guarantees that no
enum class may extend any other class.
– Of course, the compiler guarantees that because
the extends (subclass clause) cannot be used
in an enum definition:
public enum Enum { A, B, C }
Bryan Basham – Java Generics: a Deep Dive Slide 34
35. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Using Enums in Generic
Methods
● The generics idiom T extends Enum<T> is
used frequently in code involving enums:
public static <T extends Enum<T>> Function<String, T> valueOfFunct(
final Class<T> enumClass) {
return new Function<String, T>() {
public T apply(String value) {
return Enum.valueOf(enumClass, value);
}
};
}
enum MyEnum { A, B, C }
@Test
public void test() {
Function<String, MyEnum> myFunc = valueOfFunct(MyEnum.class);
assertEquals(MyEnum.B, myFunc.apply("B"));
}
● Notice the use of the enumClass argument...
Bryan Basham – Java Generics: a Deep Dive Slide 35
36. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
The Class Class
● The ultimate recursive generic type is Class.
● From the compiler's perspective:
– MyClass.class instanceof Class<MyClass>
● Of course at run-time:
– MyClass.class instanceof Class
● ...and as you just saw classes are frequently
used to “identify” a type parameter on a
generic method
Bryan Basham – Java Generics: a Deep Dive Slide 36
37. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Generics in Frameworks
Erasure Wildcards & PECS
History
Mixing w/
Raw Types
History
Simple Ex
& Theory
Complex Ex
Creating a
Odds & Sods
Generic Class Multiple Type Params
Other Types
Java Generics:
Simple Ex
a Deep Dive
Creating a Creating a
Generic Generic Method Complex Ex
Framework
PECS Reprised
Generics in Recursive
Frameworks Generic Types
GWT Simple Ex
Guava
Spring Class Enums
Bryan Basham – Java Generics: a Deep Dive Slide 37
38. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Libraries to Consider
● Guava
– Google's answer to Apache Commons
● Spring
– The ubiquitous, light-weight, enterprise
framework for Java (Java EE replacement)
● Google Web Toolkit
– Modern Java-to-JavaScript bridge framework for
building advanced, single-page Web GUIs
Bryan Basham – Java Generics: a Deep Dive Slide 38
39. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
The Guava Library
Bryan Basham – Java Generics: a Deep Dive Slide 39
40. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Guava Fundamentals
● Optional: holds an optional value
● Predicate: an interface for a query function
● Function: an interface for a generic mapping
operation
– Here's a neat little higher-order operation:
public static <A, B, C> Function<A, C> compose(
final Function<B, C> g,
final Function<A, B> f) {
return new Function<A, C>() {
public C apply(A a) {
return g.apply(f.apply(a));
}
};
}
Bryan Basham – Java Generics: a Deep Dive Slide 40
41. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Function Composition Unit Test
enum MyEnum { A, B, C }
@Test
public void test() {
Function<String, MyEnum> myEnumFunc =
Enums.valueOfFunction(MyEnum.class);
Function<String, String> upperCaseFunc =
new Function<String, String>() {
public String apply(String s) { return s.toUpperCase(); }
};
Function<String, MyEnum> cleanEnumFunc =
Functions.compose(myEnumFunc, upperCaseFunc);
assertEquals(MyEnum.B, cleanEnumFunc.apply("b"));
}
Bryan Basham – Java Generics: a Deep Dive Slide 41
42. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Guava Collections
● Range<C extends Comparable>
– A range (or "interval") defines the boundaries around a contiguous span of values of
some Comparable type; for example, "integers from 1 to 100 inclusive."
● Multiset<T>
– A collection that supports order-independent equality, like Set, but may have duplicate
elements.
● Multimap<K,V>
– A collection that maps keys to values, similar to Map, but in which each key may be
associated with multiple values.
● BiMap<K,V>
– A bimap (or "bidirectional map") is a map that preserves the uniqueness of its values
as well as that of its keys.
Bryan Basham – Java Generics: a Deep Dive Slide 42
43. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Guava Collections
● Collections2
– transform(Collection<F>, Function<? super F, T> function)
: Collection<T> : creates a new collection of transformed elements
– filter(Collection<T>, Predicate<T> function)
: Collection<T> : creates a new collection of selected elements
– And a few more...
Bryan Basham – Java Generics: a Deep Dive Slide 43
44. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Guava Collections
● Iterables
– boolean all(Collection<T> c, Predicate<T> predicate)
: queries whether all elements satisfy the predicate
– boolean any(Collection<T> c, Predicate<T> predicate)
: queries whether any element satisfies the predicate
– T find(Collection<T> c, Predicate<T> predicate, T defValue)
: finds the first value that satisfies the predicate, or returns the default
– Optional<T> tryFind(Collection<T> c, Predicate<T> predicate)
: optionally finds the first value that satisfies the predicate
– Lots more...
Bryan Basham – Java Generics: a Deep Dive Slide 44
45. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Guava Caching
● Simple API to provide in-memory caching
● Cache<K,V>: is a cache of keys to values
● CacheLoader<K,V>: is a mechanism to load
cache values
● Use a CacheBuilder to construct and
configure a cache
Bryan Basham – Java Generics: a Deep Dive Slide 45
46. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Guava Caching Example
private Cache<String, WarehouseHealth> pwhHealthCache;
@PostConstruct
private void initializeService() {
int ttlInSeconds = SpringPropertyUtils.getIntProperty(
PWH_HEALTH_CACHE_TTL, DEFAULT_PWH_HEALTH_CACHE_TTL);
pwhHealthCache =
CacheBuilder.newBuilder()
.expireAfterWrite(ttlInSeconds, TimeUnit.SECONDS)
.build(new CacheLoader<String, WarehouseHealth>() {
@Override
public WarehouseHealth load(final String key) {
List<ChannelHealth> channels =
pwhPrimaryDAO.getChannelHealth();
List<String> disabledProducts =
pwhPrimaryDAO.getDisabledContentSets();
boolean isFileWatcherRunning =
pwhPrimaryDAO.isFileWatcherRunning();
return new WarehouseHealth(channels,
disabledProducts,
isFileWatcherRunning);
}
});
}
Bryan Basham – Java Generics: a Deep Dive Slide 46
47. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
The Spring Library
Bryan Basham – Java Generics: a Deep Dive Slide 47
48. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Spring's Context and Bean Ops
● ApplicationContext and BeanFactory
– T getBean(String beanName, Class<T> requiredType)
: retrieves a Spring declared bean (creates it if necessary)
● BeanUtils
– T instantiate(Class<T> clazz)
: creates a new instance of the bean using the no-arg constructor
– T instantiateClass(Constructor<T> clazz, Object... args)
: creates a new instance of a bean with a specified constructor and arguments
Bryan Basham – Java Generics: a Deep Dive Slide 48
49. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Spring's JdbcTemplate
● If you are not using an ORM tool like Hibernate
or JPA, you should use Spring's JDBC
template API
– Removes boilerplate JDBC code
– Converts SQLException into more useful, but
silent exceptions
– Allows you to focus on the SQL and data
conversion
– RowMapper<T> is used to convert a single
ResultSet row into some Java object
Bryan Basham – Java Generics: a Deep Dive Slide 49
50. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Spring's JdbcTemplate
● General Queries
– List<T> query(String sql, Object[] args, RowMapper<T> mapper)
– T query(String sql, Object[] args, ResultSetExtractor<T> rse)
● Single Result Queries
– T queryForObject(String sql, Object[] args, Class<T> clazz)
– T queryForObject(String sql, Object[] args, RowMapper<T>
mapper)
● Multiple Result Queries
– List<T> queryForList(String sql, Object[] args, Class<T>
elementType)
Bryan Basham – Java Generics: a Deep Dive Slide 50
51. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
JdbcTemplate Example
public NovusNodeHealth getNovusHealth() {
return getJdbcTemplate().queryForObject(
NOVUS_HEALTH_QUERY, novusHealthMapper);
}
private static final String NOVUS_HEALTH_QUERY =
"SELECT novus_status, dm_load_key FROM etl_promote_status WHERE"
+ " dm_load_key in (SELECT max(dm_load_key) FROM etl_promote_status)";
private final RowMapper<NovusNodeHealth> novusHealthMapper =
new RowMapper<NovusNodeHealth>() {
public NovusNodeHealth mapRow(final ResultSet rs, final int rowNum)
throws SQLException {
Integer loadKey = rs.getInt("dm_load_key");
String status = rs.getString("novus_status");
return new NovusNodeHealth(status, loadKey, "NOVUS");
}
};
Bryan Basham – Java Generics: a Deep Dive Slide 51
52. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
The GWT Library
Bryan Basham – Java Generics: a Deep Dive Slide 52
53. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
GWT RPC Mechanism
Desktop Server
HTTP
User
...........
...........
........... «interface»
PubDatamartRPCAsync
+getStationHealth(boolean,
AsyncCallback<PubDmNodeHealthDTO>)
: void
+stopPublishingNode(
AsyncCallback<Void>)
: void
«interface» «class»
PubDatamartRPC PubDatamartRPCImpl
+getStationHealth(boolean) +getStationHealth(boolean)
: PubDmNodeHealthDTO : PubDmNodeHealthDTO
+stopPublishingNode() +stopPublishingNode()
: void : void
Bryan Basham – Java Generics: a Deep Dive Slide 53
54. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
GWT RPC
●
AsyncCallback is the heart of RPC mechanism:
public interface AsyncCallback<T> {
void onSuccess(T result);
void onFailure(Throwable caught);
}
● Usage:
AsyncCallback<PublishingDmNodeHealthDTO> callback =
new AsyncCallback<PublishingDmNodeHealthDTO>() {
public void onSuccess(final PublishingDmNodeHealthDTO result) {
pubHealthNode = result;
// TODO refresh GUI
}
public void onFailure(Throwable exception) {
// TODO handle exception
}
};
PublishingDatamartRPC.Util.getInstance()
.getStationHealth(true, callback);
Bryan Basham – Java Generics: a Deep Dive Slide 54
55. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
GWT DataGrid
● DataGrid<T>
– A table with headers and rows
– T is the type of each row
● Column<T, C>:
– A single column in the grid
– T is the row type and C is the column type
● Cell<C>:
– Defines how the cells in the grid are rendered
– C is the column type
Bryan Basham – Java Generics: a Deep Dive Slide 55
56. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
GWT DataGrid Example
usersGrid = new DataGrid<UserDTO>();
Column<UserDTO, String> userIdCOL =
new Column<UserDTO, String>(editUserLinkCell) {
public String getValue(final UserDTO row) {
return row.getUserName();
}
};
userNameCOL.setSortable(false);
userNameCOL.setCellStyleNames("columnLeft");
usersGrid.addColumn(userNameCOL, "Username");
usersGrid.setColumnWidth(userNameCOL, USERNAME_COL_SIZE, Unit.PCT);
private final Cell<String> editUserLinkCell = new AnchorTextCell() {
protected void handleClick(final Context ctx, final String value) {
EditUserPage.makeHistoryCommand(value).invoke();
}
};
Bryan Basham – Java Generics: a Deep Dive Slide 56
57. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Creating a Generic Framework
Erasure Wildcards & PECS
History
Mixing w/
Raw Types
History
Simple Ex
& Theory
Complex Ex
Creating a
Odds & Sods
Generic Class Multiple Type Params
Other Types
Subsystem Java Generics:
Frameworks Simple Ex
a Deep Dive
Creating a Creating a
Generic Generic Method Complex Ex
Multi-tier
Framework
Frameworks
PECS Reprised
Simple Ex
Generics in Recursive
Frameworks Generic Types
GWT Simple Ex
Guava
Spring Class Enums
Bryan Basham – Java Generics: a Deep Dive Slide 57
58. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Building a Generic Framework
● Frameworks appear in all applications, large
and small
● Look for redundant code and find a common
abstraction
– Sometimes this will be an abstract superclass
– Sometimes a generic class
– Sometimes a generic algorithm
– Sometimes a generic architectural metaphor
– Sometimes a shared subsystem abstraction
Bryan Basham – Java Generics: a Deep Dive Slide 58
59. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Let's start small...
● Database query request/response that
supports paging, sorting and filtering
● QueryRequest: provides input about the size
and starting point of the page to query
● QueryResult<T>: provides a single page of
data from the query
● PagedRowMapper<T>: extends Spring's
RowMapper to provide the total count of the
overall query
Bryan Basham – Java Generics: a Deep Dive Slide 59
60. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Paged Queries Framework
«value object»
QueryRequest
pageStart : int
pageSize : int
«Service» retrieve(QueryRequest): «DAO»
MyService QueryResponse<MyEntity> MyDAO Database
T=MyEntity T=MyEntity
«value object»
QueryResult «helper» «entity»
PagedRowMapper MyEntity
totalCount : int
page : List<T>
Bryan Basham – Java Generics: a Deep Dive Slide 60
61. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
The QueryResult Class
public class QueryResult<T> implements Serializable, Iterable<T> {
private final int totalCount;
private final List<T> items;
public QueryResult(final int totalCountIn, final List<T> itemsIn) {
this.totalCount = totalCountIn;
this.items = itemsIn;
}
public final int getTotalCount() {
return this.totalCount;
}
public final List<T> getItems() {
return this.items;
}
@Override
public final Iterator<T> iterator() {
return this.items.iterator();
}
}
Bryan Basham – Java Generics: a Deep Dive Slide 61
62. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
The QueryResult Class
public abstract class PagedRowMapper<T> implements RowMapper<T> {
private Integer totalCount = null;
public Integer getTotalCount() {
return (this.totalCount != null) ? this.totalCount : 0;
}
@Override
public final T mapRow(final ResultSet rs, final int rowNum)
throws SQLException {
if (this.totalCount == null) {
this.totalCount = rs.getInt("totalCount");
}
return mapEntity(rs, rowNum);
}
public abstract T mapEntity(ResultSet rs, int rowNum)
throws SQLException;
}
Bryan Basham – Java Generics: a Deep Dive Slide 62
63. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
A Multi-tier Framework
● A simple “data entry” application can take
advantage of the concept of an “Entity” (with
CRUD operations) across all application tiers:
«GWT» «GWT RPC» «Service» «DAO»
MyGUI HTTP MyRPC MySvc MyDAO DB
User
«helper»
MyTransformer
«DTO» «JPA»
MyEntityDTO MyEntity
Bryan Basham – Java Generics: a Deep Dive Slide 63
64. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
A Multi-tier Framework
T T T,ID
«interface» «interface» «interface»
DomainEntity DomainEntity DomainEntity
RPC Service DAO
+create(T):ID
+findById(ID):T
+update(T)
+delete(T)
T=User
«interface»
UserRPC T T T,ID=Long
«class» «class» «class»
AbstractDomain AbstractDomain AbstractDomain
EntityRpcImpl EntityService EntityDAO
T=User T=User T=User
«GWT RPC»
«GWT» «Service» «DAO»
UserRpc DB
UserPage HTTP UserSvc UserDAO
Impl
User
«DTO» «helper» «JPA»
UserDTO UserToDtoTfm User
Bryan Basham – Java Generics: a Deep Dive Slide 64
65. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
A Multi-tier Framework: the
Interfaces
public interface DomainEntity {
public Long getId();
public void setId(Long id);
public boolean isNew();
// other metadata properties
}
public interface DomainEntityDAO<T extends DomainEntity,
ID extends Serializable> {
public ID create(T entity);
public T findById(ID id);
public boolean delete(T entity);
public void update(T entity);
}
public interface DomainEntityService<T extends DomainEntity> {
public EntityResponse<T> create(T entity);
public EntityResponse<T> retrieveById(Long entityId);
public ServerResponse update(T entity);
public ServerResponse delete(Long entityId);
}
Bryan Basham – Java Generics: a Deep Dive Slide 65
66. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
A Multi-tier Framework: the
Interfaces
public interface EntityDTO extends Model, IsSerializable {
public static enum Depth { SURFACE, SUMMARY, TREE, DEEP };
public Long getId();
public void setId(Long id);
public Depth getDepth();
public void setDepth(Depth depth);
public boolean isNew();
public void merge(EntityDTO dto);
}
public interface DomainEntityRPC<DTO extends EntityDTO> {
public abstract GuiEntityResponse<DTO> create(DTO entity);
public abstract GuiEntityResponse<DTO> retrieveById(Long id);
public abstract GuiServerResponse update(DTO entity);
public abstract GuiServerResponse delete(Long id);
}
public interface DomainEntityRpcAsync<DTO extends EntityDTO> {
void create(DTO entity, AsyncCallback<GuiEntityResponse<DTO>> c);
void retrieveById(Long id, AsyncCallback<GuiEntityResponse<DTO>> c);
void update(DTO entity, AsyncCallback<GuiServerResponse> c);
void delete(Long id, AsyncCallback<GuiServerResponse> c);
}
Bryan Basham – Java Generics: a Deep Dive Slide 66
67. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Subsystem Framework Example
● The Incentives framework supports three
concrete subsystems in a financial application
– Apps main function is supply chain analysis
● Sales line item data
● Plus lots of reference data: products, pricing
catalogs, customers, etc
– Incentives provides decision support
● SPA: special pricing catalog assignment
● Rebates: identify SLIs for rebates to resellers
● SCA: sales rep commissions
Bryan Basham – Java Generics: a Deep Dive Slide 67
68. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Incentives Framework Concepts
Program
Contains inference and
calculation rules.
GUI Summary
Rules
objects
Inference rules
generate associations.
Incentive's
Domain
Metadata Association
Model
mind-map
Calculation rules
generate calculation
results.
Entity CalcResult
Transaction
Bryan Basham – Java Generics: a Deep Dive Slide 68
69. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Incentives “Programs” Flow
Nucleus
Txn
Eligibility
Association<Txn,Program>
Txn
Assignment
Association<Txn,Entity>
Entity
Calculation
CalculationResult
Entity
Adjustment
CalculationResult#AuditRecord
Bryan Basham – Java Generics: a Deep Dive Slide 69
70. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Incentives Analysis Model
ProgramSummary
Abstract Rebates
ProgramService ProgramDAO
ProgramEditor
DataService DataServiceDAO
ProgramTest
TransactionService TransactionDAO
ProgramReview
EligibilityEditor Rebates Rebates
ExecutionService ExecutionDAO
ReRater
Bryan Basham – Java Generics: a Deep Dive Slide 70
71. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Incentives Execution Services
«interface»
Service
T extends Entity
«interface»
IncentiveExecution «abstract»
Service AbstractBaseService
«abstract» T extends Entity
AbstractIncentive
T=ProfileEntity
ExecutionService
«interface»
RebatesExecution
Service
+generatePayoutPayment
+getPaymentHistory
T=ProfileEntity T=SpaCatalogRecord
«nucleusService» «nucleusService»
RebatesExecution SpaExecution
ServiceImpl ServiceImpl
Bryan Basham – Java Generics: a Deep Dive Slide 71
72. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Odds & Sods
Erasure Wildcards & PECS
History
Mixing w/
Raw Types
Reflection History
Simple Ex
& Theory
When not to
use generics Complex Ex
Creating a
Odds & Sods
Generic Class Multiple Type Params
Tips
Other Types
Subsystem Java Generics:
Frameworks Simple Ex
a Deep Dive
Creating a Creating a
Generic Generic Method Complex Ex
Multi-tier
Framework
Frameworks
PECS Reprised
Simple Ex
Generics in Recursive
Frameworks Generic Types
GWT Simple Ex
Guava
Spring Class Enums
Bryan Basham – Java Generics: a Deep Dive Slide 72
73. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Tips from Effective Java
● Don't use raw types in new code
● Eliminate unchecked warnings
– Removed raw types
– Or suppress
● Prefer lists to arrays
– Arrays are reified (runtime value checks);
whereas lists are erased (compile-time checks)
● Favor generic types
– Courageously create generic types and methods
Bryan Basham – Java Generics: a Deep Dive Slide 73
74. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Tips from Effective Java
● Favor generic methods
● Use bounded wildcards to increase API
flexibility
– PECS principle
● Consider type-safe heterogeneous containers
– Example API:
public interface Favorites {
public <T> void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);
}
Bryan Basham – Java Generics: a Deep Dive Slide 74
75. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
When NOT to use Generics
● Don't be afraid of complex typed data
structures, but...
● Remember that primitives are stored as
wrapped objects inside of generic collections.
● Complex computations over such complex
data structures can lead to:
– Lots of unnecessary auto-boxing
– Thus hinders performance
● But... the first rule of optimization is ???
Bryan Basham – Java Generics: a Deep Dive Slide 75
76. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Example
private void processAverages() {
int dayCount = 1;
Map<PathwayStation, Long> stationTotals =
new EnumMap<>(PathwayStation.class);
Map<PathwayStation, Map<Category, Long>> categoryTotals =
new EnumMap<>(PathwayStation.class);
// start with today's stats
for (PathwayStation s : PathwayStation.values()) {
stationTotals.put(s, dailyLoadStats.getStationTotal(s));
Map<Category, Long> catTotalsByStation = new HashMap<>();
categoryTotals.put(s, catTotalsByStation);
for (Category c : pathwayConfig.getCategories()) {
catTotalsByStation.put(c, dailyLoadStats.getCategoryTotal(s, c));
}
}
// process the averages
for (DailyLoadStatistics dls : loadStatsHistory) {
cayCount++;
// accumulate station totals
for (PathwayStation s : PathwayStation.values()) {
stationTotals.put(s, stationTotals.get(s)+dls.getStationTotal(s));
// accumulate category totals
Map<Category, Long> catTotalsByStation = categoryTotals.get(s);
for (Category c : pathwayConfig.getCategories()) {
catTotalsByStation.put(c, catTotalsByStation.get(c)
+dls.getCategoryTotal(s, c));
// MORE...
Bryan Basham – Java Generics: a Deep Dive Slide 76
77. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Example Refactored
private void processAverages() {
int dayCount = 1;
List<Category> categories = pathwayConfig.getCategories();
long[] stationTotals = new long[PathwayStation.values().length];
long[][] categoryTotals = new long[PathwayStation.values().length][];
// start with today's stats
for (PathwayStation s : PathwayStation.values()) {
stationTotals[s.ordinal()] = dailyLoadStats.getStationTotal(s);
// categories
long[] catTotalsByStation = new long[categories.size()];
categoryTotals[s.ordinal()] = catTotalsByStation;
int cc = 0;
for (Category c : pathwayConfig.getCategories()) {
catTotalsByStation[cc++] = dailyLoadStats.getCategoryTotal(s, c);
}
}
// process the averages
for (DailyLoadStatistics dls : loadStatsHistory) {
dayCount++;
// accumulate station totals
for (PathwayStation s : PathwayStation.values()) {
stationTotals[s.ordinal()] += dls.getStationTotal(s);
// accumulate category totals
// MORE... you get the idea
Bryan Basham – Java Generics: a Deep Dive Slide 77
78. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Reflection
● Because generic type arguments are erased at
runtime, you cannot perform reflection on an
object instance.
● However, you can perform reflection on the
type parameters of generic classes and
methods.
Bryan Basham – Java Generics: a Deep Dive Slide 78
79. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Reflection Example
class GenericClass<T extends Enum<T>, N extends Number> { }
public class ReflectionTest {
@Test
public void test1() {
Class<?> clazz = GenericClass.class;
TypeVariable<?>[] typeParams = clazz.getTypeParameters();
// test type params
TypeVariable<?> first = typeParams[0];
assertEquals("T", first.getName());
Type firstBoundsType = first.getBounds()[0];
assertTrue("first param type is bound by a parameterized type",
(firstBoundsType instanceof ParameterizedType));
assertEquals(Enum.class,
((ParameterizedType)firstBoundsType).getRawType());
TypeVariable<?> second = typeParams[1];
assertEquals("N", second.getName());
Type secondBoundsType = second.getBounds()[0];
assertTrue("second param type is bound by a standard type",
!(secondBoundsType instanceof ParameterizedType));
assertEquals(Number.class, secondBoundsType);
}
}
Bryan Basham – Java Generics: a Deep Dive Slide 79
80. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Q&A
Erasure Wildcards & PECS
History
Mixing w/
Raw Types
Reflection History
Simple Ex
& Theory
When not to
use generics Complex Ex
Creating a
Odds & Sods
Generic Class Multiple Type Params
Tips
Other Types
Subsystem Java Generics:
Frameworks Simple Ex
a Deep Dive
Creating a Creating a
Generic Generic Method Complex Ex
Multi-tier
Framework
Frameworks
PECS Reprised
Simple Ex
Generics in Recursive
Frameworks Generic Types
GWT Simple Ex
Guava
Spring Class Enums
Bryan Basham – Java Generics: a Deep Dive Slide 80
81. RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy
Resources
● Wikipedia
● Official Java Tutorial
● Generics in the Java Programming Language (tutorial by Gilad Bracha)
● Angelika Langer's Java Generics FAQ
● JSR 14: Add Generic Types to the Java Programming Language
● Book: Java Generics (O'Reilly Media)
● More Wikipedia:
– Type Systems
– Generic Programming
● StackOverflow on PECS principle
Bryan Basham – Java Generics: a Deep Dive Slide 81