Running on Java 24-ea+21-2447 (Preview)
Home of The JavaSpecialists' Newsletter

140Book Review: Java Generics and Collections

Author: Dr. Heinz M. KabutzDate: 2007-03-08Java Version: 5Category: Book Review
 

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

javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.

Book Review: Java Generics and Collections [ISBN 0596527756]

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 [ISBN 0596527756] 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 [ISBN 0596527756] , 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)!

 

Comments

We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)

When you load these comments, you'll be connected to Disqus. Privacy Statement.

Related Articles

Browse the Newsletter Archive

About the Author

Heinz Kabutz Java Conference Speaker

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Superpack '23

Superpack '23 Our entire Java Specialists Training in one huge bundle more...

Free Java Book

Dynamic Proxies in Java Book
Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

We can help make your Java application run faster and trouble-shoot concurrency and performance bugs...