Java Generics: a deep dive
Upcoming SlideShare
Loading in...5
×
 

Java Generics: a deep dive

on

  • 1,670 views

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 ...

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).

Statistics

Views

Total Views
1,670
Views on SlideShare
1,669
Embed Views
1

Actions

Likes
2
Downloads
86
Comments
0

1 Embed 1

https://www.linkedin.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Java Generics: a deep dive Java Generics: a deep dive Presentation Transcript

  • 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/SoftwareAlchemistBryan Basham – Java Generics: a Deep Dive Slide 1
  • 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 TypesBryan Basham – Java Generics: a Deep Dive Slide 2
  • 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 designsBryan Basham – Java Generics: a Deep Dive Slide 3
  • 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 errorBryan Basham – Java Generics: a Deep Dive Slide 4
  • 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
  • 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
  • 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
  • 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
  • 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 valuesBryan Basham – Java Generics: a Deep Dive Slide 9
  • 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 ● Dont mix raw types with generic types – Unless integrating with legacy APIs – NEVER use raw types in new codeBryan Basham – Java Generics: a Deep Dive Slide 10
  • 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 TypesBryan Basham – Java Generics: a Deep Dive Slide 11
  • 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
  • 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 classBryan Basham – Java Generics: a Deep Dive Slide 13
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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 librariesBryan Basham – Java Generics: a Deep Dive Slide 20
  • 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
  • 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 – EnumsBryan Basham – Java Generics: a Deep Dive Slide 22
  • 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 TypesBryan Basham – Java Generics: a Deep Dive Slide 23
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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 ClassBryan Basham – Java Generics: a Deep Dive Slide 31
  • 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 dont handle them correctlyBryan Basham – Java Generics: a Deep Dive Slide 32
  • 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
  • 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
  • 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
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy The Class Class ● The ultimate recursive generic type is Class. ● From the compilers 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 methodBryan Basham – Java Generics: a Deep Dive Slide 36
  • 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 EnumsBryan Basham – Java Generics: a Deep Dive Slide 37
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy Libraries to Consider ● Guava – Googles 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 GUIsBryan Basham – Java Generics: a Deep Dive Slide 38
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy The Guava LibraryBryan Basham – Java Generics: a Deep Dive Slide 39
  • 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 – Heres 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
  • 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
  • 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
  • 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
  • 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
  • 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 cacheBryan Basham – Java Generics: a Deep Dive Slide 45
  • 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
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy The Spring LibraryBryan Basham – Java Generics: a Deep Dive Slide 47
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy Springs 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 argumentsBryan Basham – Java Generics: a Deep Dive Slide 48
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy Springs JdbcTemplate ● If you are not using an ORM tool like Hibernate or JPA, you should use Springs 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 objectBryan Basham – Java Generics: a Deep Dive Slide 49
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy Springs 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
  • 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
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy The GWT LibraryBryan Basham – Java Generics: a Deep Dive Slide 52
  • 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 : voidBryan Basham – Java Generics: a Deep Dive Slide 53
  • 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
  • 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 typeBryan Basham – Java Generics: a Deep Dive Slide 55
  • 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
  • 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 EnumsBryan Basham – Java Generics: a Deep Dive Slide 57
  • 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 abstractionBryan Basham – Java Generics: a Deep Dive Slide 58
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy Lets 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 Springs RowMapper to provide the total count of the overall queryBryan Basham – Java Generics: a Deep Dive Slide 59
  • 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
  • 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
  • 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
  • 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 MyEntityBryan Basham – Java Generics: a Deep Dive Slide 63
  • 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 ImplUser «DTO» «helper» «JPA» UserDTO UserToDtoTfm UserBryan Basham – Java Generics: a Deep Dive Slide 64
  • 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
  • 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
  • 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 commissionsBryan Basham – Java Generics: a Deep Dive Slide 67
  • 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. Incentives Domain Metadata Association Model mind-map Calculation rules generate calculation results. Entity CalcResult TransactionBryan Basham – Java Generics: a Deep Dive Slide 68
  • 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#AuditRecordBryan Basham – Java Generics: a Deep Dive Slide 69
  • 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 ReRaterBryan Basham – Java Generics: a Deep Dive Slide 70
  • 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 ServiceImplBryan Basham – Java Generics: a Deep Dive Slide 71
  • 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 EnumsBryan Basham – Java Generics: a Deep Dive Slide 72
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy Tips from Effective Java ● Dont 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 methodsBryan Basham – Java Generics: a Deep Dive Slide 73
  • 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
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy When NOT to use Generics ● Dont 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
  • 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 todays 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
  • 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 todays 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 ideaBryan Basham – Java Generics: a Deep Dive Slide 77
  • 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
  • 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
  • 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 EnumsBryan Basham – Java Generics: a Deep Dive Slide 80
  • RJUG : 12-Dec-2012 © Copyright 2012, Software Alchemy Resources ● Wikipedia ● Official Java Tutorial ● Generics in the Java Programming Language (tutorial by Gilad Bracha) ● Angelika Langers Java Generics FAQ ● JSR 14: Add Generic Types to the Java Programming Language ● Book: Java Generics (OReilly Media) ● More Wikipedia: – Type Systems – Generic Programming ● StackOverflow on PECS principleBryan Basham – Java Generics: a Deep Dive Slide 81