View
2.461
Download
4
Category
Tags:
Preview:
DESCRIPTION
If you've programmed in Java in the past decade then you know what generic types are. Generics are used everywhere but rarely understood on a deep level. In this talk, Bryan will show not only classic "container" generic classes but also how to build simple, but highly flexible frameworks in all tiers (GUI, Service and DAO tiers).
Citation preview
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 1
© Copyright 2012, Software Alchemy
History& Theory
Java Generics:a Deep Dive
Creating aGeneric Method
Creating aGeneric Class
RecursiveGeneric Types
Generics inFrameworks
Creating aGeneric
Framework
Odds & Sods
Java Generics
Bryan BashamSoftware Alchemy
basham47@gmail.com
http://www.linkedin.com/in/SoftwareAlchemist
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 2
© Copyright 2012, Software Alchemy
Java Generics:a Deep Dive
Creating aGeneric Method
RecursiveGeneric Types
Generics inFrameworks
Creating aGeneric
Framework
Odds & Sods
Mixing w/Raw Types
ErasureHistory
Wildcards & PECS
History& Theory
Creating aGeneric Class
History & Theory
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 3
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 4
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 5
© 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...} }
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 6
© Copyright 2012, Software Alchemy
Terminology
● Generic type:public class LispList<T> { ... }
public class Pair<T1, T2> { ... }
● Parameterized type: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, Map<RecencyCategory, EnumMap<RfmAnalysisStatistic, Number>>> rfmContent = new HashMap<>();
Type Argument(required in Java 5 & 6)
“the diamond”
Type Parameter
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 7
© Copyright 2012, Software Alchemy
More Terminology
● Generic method:public void printPair(Pair<?,?> p) { System.out.println("(" + p.getFirst() + "," + p.getSecond() + ")");}
● Bounded wildcards:public interface DomainEntityDAO<T extends DomainEntity> { public long create(T entity); public T findById(long id);}
public static <T> void flush(Collection<T> coll, Sink<? super T> sink) { // flush all elements in the collection to the sink}
Wildcard Argument(unbounded)
Upper-Bound Wildcard
Lower-Bound WildcardGeneric Method Type Parameter
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 8
© 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?// from the java.util.Collections API:
public static <T> T max(Collection<? extends T> collection, Comparator<? super T> comparator)
● More explanation: click here
The collection produces elementsto compare to find the max.
The comparator consumes elementswhile performing the comparison.
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 9
© Copyright 2012, Software Alchemy
Mixing Raw Types with Generics
● A raw type is a use of a generic type without type arguments:
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
Raw Type
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 10
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 11
© Copyright 2012, Software Alchemy
Java Generics:a Deep Dive
Creating aGeneric Method
RecursiveGeneric Types
Generics inFrameworks
Creating aGeneric
Framework
Odds & Sods
Mixing w/Raw Types
ErasureHistory
Wildcards & PECS
History& Theory
Complex Ex
Simple Ex
Multiple Type Params
Other Types
Creating aGeneric Class
Creating a Generic Class
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 12
© 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(); } }}
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 13
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 14
© 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; }}
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 15
© 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()); }
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 16
© 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(); } }}
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 17
© 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); // int count = 0; for (int value : list) { assertEquals(count++, value); } }
You can use any Iterable as thetarget of a for-each statement.
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 18
© 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; }}
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 19
© 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()); }
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 20
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 21
© 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()); }
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 22
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 23
© Copyright 2012, Software Alchemy
Java Generics:a Deep Dive
RecursiveGeneric Types
Generics inFrameworks
Creating aGeneric
Framework
Odds & Sods
Mixing w/Raw Types
ErasureHistory
Wildcards & PECS
History& Theory
Complex Ex
Simple Ex
Multiple Type Params
Other Types
Creating aGeneric Class
Complex Ex
Simple Ex
PECS Reprised
Creating aGeneric Method
Creating a Generic Method
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 24
© 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?
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 25
© 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; }
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 26
© 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?
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 27
© 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; }
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 28
© 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 foranonymous inner classes; that was the bugtwo slides ago.
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 29
© 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?
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 30
© 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.
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 31
© Copyright 2012, Software Alchemy
Java Generics:a Deep Dive
Generics inFrameworks
Creating aGeneric
Framework
Odds & Sods
Mixing w/Raw Types
ErasureHistory
Wildcards
History& Theory
Complex Ex
Simple Ex
Multiple Type Params
Other Types
Creating aGeneric Class
Complex Ex
Simple Ex
PECS Reprised
Creating aGeneric Method
Enums
Simple Ex
Class
RecursiveGeneric Types
Recursive Generic Types
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 32
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 33
© 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);
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 34
© 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 }
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 35
© 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...
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 36
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 37
© Copyright 2012, Software Alchemy
Java Generics:a Deep Dive
Creating aGeneric
Framework
Odds & Sods
Mixing w/Raw Types
ErasureHistory
Wildcards & PECS
History& Theory
Complex Ex
Simple Ex
Multiple Type Params
Other Types
Creating aGeneric Class
Complex Ex
Simple Ex
PECS Reprised
Creating aGeneric Method
Enums
Simple Ex
Class
RecursiveGeneric Types
SpringGuava
GWT
Generics inFrameworks
Generics in Frameworks
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 38
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 39
© Copyright 2012, Software Alchemy
The Guava Library
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 40
© 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)); } }; }
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 41
© 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")); }
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 42
© 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.
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 43
© 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...
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 44
© 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...
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 45
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 46
© 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); } }); }
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 47
© Copyright 2012, Software Alchemy
The Spring Library
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 48
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 49
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 50
© 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)
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 51
© 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"); }};
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 52
© Copyright 2012, Software Alchemy
The GWT Library
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 53
© Copyright 2012, Software Alchemy
«interface»PubDatamartRPCAsync
+getStationHealth(boolean, AsyncCallback<PubDmNodeHealthDTO>) : void+stopPublishingNode( AsyncCallback<Void>) : void
User
ServerDesktop
.................................
HTTP
«interface»PubDatamartRPC
+getStationHealth(boolean) : PubDmNodeHealthDTO+stopPublishingNode() : void
«class»PubDatamartRPCImpl
+getStationHealth(boolean) : PubDmNodeHealthDTO+stopPublishingNode() : void
GWT RPC Mechanism
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 54
© 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);
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 55
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 56
© 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(); }};
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 57
© Copyright 2012, Software Alchemy
Java Generics:a Deep Dive
Odds & Sods
Mixing w/Raw Types
ErasureHistory
Wildcards & PECS
History& Theory
Complex Ex
Simple Ex
Multiple Type Params
Other Types
Creating aGeneric Class
Complex Ex
Simple Ex
PECS Reprised
Creating aGeneric Method
Enums
Simple Ex
Class
RecursiveGeneric Types
SpringGuava
GWT
Generics inFrameworks
Multi-tierFrameworks
Simple Ex
SubsystemFrameworks
Creating aGeneric
Framework
Creating a Generic Framework
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 58
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 59
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 60
© Copyright 2012, Software Alchemy
Paged Queries Framework
Database«DAO»
MyDAO
«entity»MyEntity
«value object»QueryResult
T=MyEntity
retrieve(QueryRequest):QueryResponse<MyEntity>
«Service»MyService
«helper»PagedRowMapper
T=MyEntity
«value object»QueryRequest
pageStart : intpageSize : int
totalCount : intpage : List<T>
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 61
© 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(); }}
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 62
© 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;}
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 63
© 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:
DB«DAO»
MyDAO
«JPA»MyEntity
«Service»MySvc
«DTO»MyEntityDTO
User
«GWT RPC»MyRPC
«GWT»MyGUI HTTP
«helper»MyTransformer
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 64
© Copyright 2012, Software Alchemy
A Multi-tier Framework
DB«DAO»
UserDAO
«JPA»User
T=User
«Service»UserSvc
«DTO»UserDTO
User
«GWT RPC»UserRpc
Impl«GWT»
UserPage HTTP
«helper»UserToDtoTfm
«interface»DomainEntity
DAO+create(T):ID+findById(ID):T+update(T)+delete(T)
T,ID
«class»AbstractDomainEntityDAO
T,ID=Long
T=UserT=User
«class»AbstractDomainEntityService
T
«interface»DomainEntity
Service
T
«class»AbstractDomainEntityRpcImpl
T
«interface»DomainEntity
RPC
T
«interface»UserRPC
T=User
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 65
© 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);}
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 66
© 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);}
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 67
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 68
© Copyright 2012, Software Alchemy
Incentives Framework Concepts
Incentive'sDomainModel
mind-map
Program
Rules
Association
CalcResult
Transaction
Entity
Metadata
GUI Summaryobjects
Contains inference andcalculation rules.
Inference rulesgenerate associations.
Calculation rulesgenerate calculation
results.
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 69
© Copyright 2012, Software Alchemy
Incentives “Programs” Flow
Eligibility
Association<Txn,Program>
Nucleus
Assignment
Association<Txn,Entity>
Calculation
CalculationResult
Txn
Txn
Entity
Adjustment
CalculationResult#AuditRecord
Entity
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 70
© Copyright 2012, Software Alchemy
Incentives Analysis Model
RebatesExecutionService
TransactionService
AbstractProgramService
DataService
ProgramSummary
ProgramReview
ProgramEditor
ProgramTest
RebatesProgramDAO
DataServiceDAO
TransactionDAO
RebatesExecutionDAO
EligibilityEditor
ReRater
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 71
© Copyright 2012, Software Alchemy
Incentives Execution Services
«interface»IncentiveExecution
Service
«nucleusService»RebatesExecution
ServiceImpl
«nucleusService»SpaExecutionServiceImpl
T extends Entity
«interface»RebatesExecution
Service
«abstract»AbstractIncentiveExecutionService
T extends Entity
T=ProfileEntity
T=ProfileEntity T=SpaCatalogRecord
«interface»Service
«abstract»AbstractBaseService
+generatePayoutPayment+getPaymentHistory
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 72
© Copyright 2012, Software Alchemy
Java Generics:a Deep Dive
Mixing w/Raw Types
ErasureHistory
Wildcards & PECS
History& Theory
Complex Ex
Simple Ex
Multiple Type Params
Other Types
Creating aGeneric Class
Complex Ex
Simple Ex
PECS Reprised
Creating aGeneric Method
Enums
Simple Ex
Class
RecursiveGeneric Types
SpringGuava
GWT
Generics inFrameworks
Multi-tierFrameworks
Simple Ex
SubsystemFrameworks
Creating aGeneric
Framework
ReflectionWhen not touse generics
TipsOdds & Sods
Odds & Sods
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 73
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 74
© 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);}
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 75
© 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 ???
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 76
© 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...
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 77
© 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
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 78
© 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.
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 79
© 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); }}
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 80
© Copyright 2012, Software Alchemy
Java Generics:a Deep Dive
Mixing w/Raw Types
ErasureHistory
Wildcards & PECS
History& Theory
Complex Ex
Simple Ex
Multiple Type Params
Other Types
Creating aGeneric Class
Complex Ex
Simple Ex
PECS Reprised
Creating aGeneric Method
Enums
Simple Ex
Class
RecursiveGeneric Types
SpringGuava
GWT
Generics inFrameworks
Multi-tierFrameworks
Simple Ex
SubsystemFrameworks
Creating aGeneric
Framework
ReflectionWhen not touse generics
TipsOdds & Sods
Q & A
RJUG : 12-Dec-2012
Bryan Basham – Java Generics: a Deep Dive Slide 81
© 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
Recommended