Java Specialists' Java Training Europehome of the java specialists' newsletter

The Java Specialists' Newsletter
Issue 1402007-03-08 Category: Book Review Java version: 5+

GitHub Subscribe Free RSS Feed

Book Review: Java Generics and Collections

by Dr. Heinz M. Kabutz
Abstract:
Java Generics and Collections is the "companion book" to The Java Specialists' Newsletter. A well written book that explains generics really nicely, including some difficult concepts. In addition, they cover all the new collection classes up to Java 6 Mustang.

Welcome to the 140th edition of The Java(tm) Specialists' Newsletter, now sent to 113 countries with the recent addition of Jordan. This morning, my wife Helene, our baby Evangeline and I went for a lovely walk on Kalathas Beach, a versatile and wholly pleasant beach, close to where we live. The sand is soft, the water shallow (perfect for kids) but gets deeper after a while (perfect for dad). There is a rocky outcrop a bit further out, from which you can jump into the water. There are more fish than at other beaches. They have a fantastic restaurant on the beach that serves genuine Cretan cooking. It is a great all-round beach :) Here are some pictures of Kalathas Beach: http://www.javaspecialists.eu/crete/kalathas.jsp.

Join us on Crete (or via webinar) for advanced Core Java Courses:Concurrency Specialists Course 1-4 April 2014 and Java Specialists Master Course 20-23 May 2014.

Book Review: Java Generics and Collections

The companion book to The Java(tm) Specialists' Newsletter!

Occasionally, books are written that appeal to Java specialists (unfortunately not often enough). Java Generics and Collections is such a book. Here are some fascinating nuggets that I found - there are many more.

Explicit Parameters

Mixing generic methods and varargs produces some side effects that result in strange syntax, which most Java programmers don't know. Let's start with the following class:

import java.util.*;

public class Lists {
  public static <T> List<T> toList(T... arr) {
    List<T> list = new ArrayList<T>();
    for (T t : arr) list.add(t);
    return list;
  }
}
  

We can now use this to produce lists of ints or Strings:

List<Integer> ints = Lists.toList(1, 2, 3);
List<String> words = Lists.toList("hello", "world");
  

At runtime, the arguments are packed into an array, which is passed to the method toList().

Now comes the catch: What is the generic type that comes back when you pass different types of objects to the toList() method, for example:

List<?> something = Lists.toList("one", 2, 3.0);
  

You would expect that you can simply write:

List<Object> objects = Lists.toList("one", 2, 3.0); // does not compile!
  

However, this is not possible, since there is a lower common class, in this case java.io.Serializable. If you want to bind T to a particular class, for example Object, you need to use explicit parameters:

List<Object> objects = Lists.<Object>toList("one", 2, 3.0);
  

You cannot mix explicit parameters with static imports. The Java grammar requires that type parameters may appear only in method invocations that use a dotted form.

Although I am certain this appears in other publications, this book is the first place I read such a clear explanation.

Migrating Legacy Code

In chapter 5: "Evolution, Not Revolution", we see various approaches we can use when migrating from legacy code to generics.

Migrating is migrane and grating rolled into one!

They offer various solutions for legacy and generic clients and libraries combinations. The most interesting combination is where you have a legacy library and a generic client. There are various alternatives:

  1. Evolving a library using minimal changes: Change the method declarations, but keep the actual code the same. Use a generous helping of @SuppressWarnings("unchecked) annotations. We can only do that if we have access to the source.
  2. Evolving a library using stubs: Write stubs with generic signatures but no bodies. We compile the generic client against the generic signatures, but run the code against the legacy class files. We can do that when we do not have access to the source.
  3. Evolving a library using wrappers: Here we leave the legacy source and class files unchanged, and provide a wrapper class that accesses the legacy class via delegation. This is actually an anti-pattern and brings with it many problems. In the book they warn you against its use.

The book then continues by describing reification and the effects this has. After that comes reflection with generics. Both are interesting chapters for Java specialists.

Design Patterns & Generics

In chapter 9, we see several design patterns implemented with generics, including our popular strategy pattern newsletter, which is reprinted in the book (with permission). They also show the Visitor, Interpreter, Function and Observer patterns.

Collections

The book then goes on to Java 5 and Java 6 collections, including the latest Deque and NavigableMap classes.

Each collection chapter ends with a table of big O notation for each operations. This is only meant as a guideline in deciding which implementation to choose. TreeMap can quite easily outperform HashMap depending on the complexity of the hashCode(), equals() and compareTo() methods.

Regular and Jumbo EnumSet

One area that the book did not pick up on is the significance of the EnumSet.noneOf() method. This is actually a factory method that returns different implementations of EnumSet depending on the key universe. If the key universe is larger than 64, it creates a JumboEnumSet, if it is smaller, a RegularEnumSet. The JumboEnumSet represents the bitset as a long[], whereas the RegularEnumSet simply contains a long. I suspect that the authors felt this going too deep into implementation details.

import java.util.EnumSet;

public class EnumSetTest {
  public enum SMALL {
    A0, A1, A2
  }

  public enum MEDIUM {
    A00, A01, A02, A03, A04, A05, A06, A07, A08, A09,
    A10, A11, A12, A13, A14, A15, A16, A17, A18, A19,
    A20, A21, A22, A23, A24, A25, A26, A27, A28, A29,
    A30, A31, A32, A33, A34, A35, A36, A37, A38, A39,
    A40, A41, A42, A43, A44, A45, A46, A47, A48, A49,
    A50, A51, A52, A53, A54, A55, A56, A57, A58, A59,
    A60, A61, A62, A63
  }

  public enum LARGE {
    A00, A01, A02, A03, A04, A05, A06, A07, A08, A09,
    A10, A11, A12, A13, A14, A15, A16, A17, A18, A19,
    A20, A21, A22, A23, A24, A25, A26, A27, A28, A29,
    A30, A31, A32, A33, A34, A35, A36, A37, A38, A39,
    A40, A41, A42, A43, A44, A45, A46, A47, A48, A49,
    A50, A51, A52, A53, A54, A55, A56, A57, A58, A59,
    A60, A61, A62, A63, A64
  }

  public static void main(String[] args) {
    System.out.println(EnumSet.noneOf(SMALL.class).getClass());
    System.out.println(EnumSet.noneOf(MEDIUM.class).getClass());
    System.out.println(EnumSet.noneOf(LARGE.class).getClass());
  }
}
  

When we run this, we see as output:

    class java.util.RegularEnumSet
    class java.util.RegularEnumSet
    class java.util.JumboEnumSet
  

The book has a lot more fascinating information about generics and collections than I could describe in one newsletter.

If possible, please consider supporting the authors by purchasing the book, and not downloading the PDF from the internet somewhere :-)

Kind regards from Europe

Heinz

P.S. Have you already bought the book? Let me know if you liked it (or not)!

Book Review Articles Related Java Course

Java Master
Java Concurrency
Design Patterns
In-House Courses



© 2010-2014 Heinz Kabutz - All Rights Reserved Sitemap
Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners. JavaSpecialists.eu is not connected to Oracle, Inc. and is not sponsored by Oracle, Inc.
@CORE_THE_BAND #RBBJGR