Java Generics and Collections
andrew cooke writes "Java 6 was recently
released, but many programmers are still exploring the features
introduced in Java 5 — probably the most significant changes in
the language's twelve year history. Amongst those changes (enumerations,
auto-boxing, foreach, varargs) generics was the most far-reaching,
introducing generic programming in a simpler, safer way than C++
templates and, unlike generics in C#, maintaining backwards (and
forwards) compatibility with existing Java code." Read on for the rest of Andrew's review.
Java Generics and Collections
author
Maurice Naftalin, Philip Wadler
pages
273
publisher
O'Reilly Media, Inc.
rating
9/10
reviewer
Andrew Cooke
ISBN
978-0-596-52775-4
summary
Guide to Java generics; also includes interesting discussion of collection classes.
Given the history of Generic Java, Naftalin and Wadler's Java Generics and Collections has a distinguished pedigree. In this review I'll argue that this is a new classic.
If you're a Java programmer you've probably heard of generics, an extension to the type system that was introduced in Java 5. They give you, as a programmer, a way to write code even when you don't know exactly what classes will be used.
The obvious example is collections — the author of a List class has no idea what type of objects will be stored when the code is used.
Before generics, if you wanted to write code that handled unknown classes you had to use make use of inheritance: write the code as if it would get Objects, and then let the caller cast the result as necessary. Since casts happen at runtime any mistakes may cause a runtime error (a ClassCastException).
Generics fix this. They let you write code in which the classes are named (parameters) and the compiler can then check that the use of these class parameters is consistent in your program. So if you have a List of Foo instances you write List<Foo> and the compiler knows that when you read that list you will receive a Foo, not an Object.
I'll get to the book in a moment, but first a little history. If you know any type theory — particularly as used in functional languages like ML and Haskell — then you'll recognize my quick description above as parametric polymorphism. You'll also know that it is incredibly useful, and wonder how Java programmers could ever have managed without it.
Which explains why Philip Wadler, one of the people responsible for Haskell, was part of a team that wrote GJ (Generic Java), one of the experimental Java mutations (others included PolyJ and Pizza) that, back in the day (late 90s) helped explore how parametric polymorphism could be added to Java, and which formed the basis for the generics introduced in Java 5.
So if you want to understand generics, Wadler is your man. Which, in turn, explains why I jumped at the chance to review O'Reilly's Java Generics and Collections, by Maurice Naftalin and Philip Wadler.
This is a moderately slim book (just under 300 pages). It looks like any other O'Reilly work — the animal is an Alligator this time. It's well organized, easy to read, and has a decent index.
There's an odd discrepancy, though: Wadler is the generics Guru; this is going to be `the generics reference'; generics are sexy (in relative terms — we're talking Java here) and collections are not; the title has "Java Generics" in great big letters with "and Collections" in little tiny ones down in a corner. Yet very nearly half this book is dedicated to collections.
Generics is a great, practical read. It starts simply, introducing a range of new features in Java 5, and then builds rapidly.
If you are completely new to generics, you'll want to read slowly. Everything is here, and it's very clear and friendly, but there are not the chapters of simple, repeated examples you might find in a fatter book. Within just 30 pages you meet pretty much all of generics, including wildcards and constraints.
If that makes your head spin, don't worry. Read on. The next hundred or so pages don't introduce any new syntax, but instead discuss a wide range of related issues. The chapters on Comparisons and Bounds and Declarations contain more examples that will help clarify what generics do. And the following chapters on Evolution, Reification, and Reflection will explain exactly why.
So the first seven chapters introduce generics and then justify the implementation — any programmer that takes the time to understand this will have a very solid base in generics.
There are even some interesting ideas on how Java could have evolved differently — section 6.9 Arrays as a Deprecated Type presents a strong case for removing arrays from the language. It's a tribute to the clarity and depth of this book that the reader is able to follow detailed arguments about language design. Fascinating stuff.
The next two chapters, however, were my favorites. Effective Generics and Design Patterns give sensible, practical advice on using generics in your work, including the best explanation of <X extends Foo<X>> I've seen yet (so if you don't know what I am talking about here, read the book).
(A practical word of advice — if at all possible, use Java 6 with generics. Java 5 has a sneaky bug).
The Collections part of the book was more along O'Reilly's `Nutshell' lines: the different chapters explore different collection types in detail. I must admit that at first I skipped this — it looked like API docs re-hashed to extend the size of the book.
Then I felt bad, because I was supposed to be reviewing this book (full disclosure: if you review a book for Slashdot you get to keep it). And you know what? It turned out to be pretty interesting. I've programmed in Java for (too many) years, and I guess I've not been quite as dedicated to tracking how the library has changed as I should have been — I learned a lot.
Again, a wide range of readers are welcome. This is more than a summary of the Javadocs, ranging from thumbnail sketches of trees and hashtables to a discussion of containers intended for multi-threaded programming.
The way I see it now, this part is a bonus: the first half, on generics, makes this book one of the standards; the second half is an extra treat I'm glad I stumbled across (I guess if you're some kind of weird collection-fetishist maybe it's even worth buying the book for).
I've used generics since the first beta release of Java 5 and had experience with parametric polymorphism in functional languages before that (in other words, I can tell my co- from my contra-variance). So I guess I'm heading towards the more expert end of the spectrum and I was worried I'd find the book boring. It wasn't. After claiming to be expert I don't want to spoil things with evidence that I'm actually stupid, but reading this book cleared up a few `misunderstandings' I'd had. I wish I had read it earlier.
If you're new to generics, and you don't mind thinking, I recommend this book. If you're a Java programmer who's a bit confused by <? super Foo> then this is the book for you.
The only people who shouldn't read this are people new to Java. You need to go elsewhere first. This is not a book for complete beginners. This is a great book in the classic — practical, concise and intelligent — O'Reilly mould.
You can purchase Java Generics and Collections from amazon.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
Given the history of Generic Java, Naftalin and Wadler's Java Generics and Collections has a distinguished pedigree. In this review I'll argue that this is a new classic.
If you're a Java programmer you've probably heard of generics, an extension to the type system that was introduced in Java 5. They give you, as a programmer, a way to write code even when you don't know exactly what classes will be used.
The obvious example is collections — the author of a List class has no idea what type of objects will be stored when the code is used.
Before generics, if you wanted to write code that handled unknown classes you had to use make use of inheritance: write the code as if it would get Objects, and then let the caller cast the result as necessary. Since casts happen at runtime any mistakes may cause a runtime error (a ClassCastException).
Generics fix this. They let you write code in which the classes are named (parameters) and the compiler can then check that the use of these class parameters is consistent in your program. So if you have a List of Foo instances you write List<Foo> and the compiler knows that when you read that list you will receive a Foo, not an Object.
I'll get to the book in a moment, but first a little history. If you know any type theory — particularly as used in functional languages like ML and Haskell — then you'll recognize my quick description above as parametric polymorphism. You'll also know that it is incredibly useful, and wonder how Java programmers could ever have managed without it.
Which explains why Philip Wadler, one of the people responsible for Haskell, was part of a team that wrote GJ (Generic Java), one of the experimental Java mutations (others included PolyJ and Pizza) that, back in the day (late 90s) helped explore how parametric polymorphism could be added to Java, and which formed the basis for the generics introduced in Java 5.
So if you want to understand generics, Wadler is your man. Which, in turn, explains why I jumped at the chance to review O'Reilly's Java Generics and Collections, by Maurice Naftalin and Philip Wadler.
This is a moderately slim book (just under 300 pages). It looks like any other O'Reilly work — the animal is an Alligator this time. It's well organized, easy to read, and has a decent index.
There's an odd discrepancy, though: Wadler is the generics Guru; this is going to be `the generics reference'; generics are sexy (in relative terms — we're talking Java here) and collections are not; the title has "Java Generics" in great big letters with "and Collections" in little tiny ones down in a corner. Yet very nearly half this book is dedicated to collections.
Generics is a great, practical read. It starts simply, introducing a range of new features in Java 5, and then builds rapidly.
If you are completely new to generics, you'll want to read slowly. Everything is here, and it's very clear and friendly, but there are not the chapters of simple, repeated examples you might find in a fatter book. Within just 30 pages you meet pretty much all of generics, including wildcards and constraints.
If that makes your head spin, don't worry. Read on. The next hundred or so pages don't introduce any new syntax, but instead discuss a wide range of related issues. The chapters on Comparisons and Bounds and Declarations contain more examples that will help clarify what generics do. And the following chapters on Evolution, Reification, and Reflection will explain exactly why.
So the first seven chapters introduce generics and then justify the implementation — any programmer that takes the time to understand this will have a very solid base in generics.
There are even some interesting ideas on how Java could have evolved differently — section 6.9 Arrays as a Deprecated Type presents a strong case for removing arrays from the language. It's a tribute to the clarity and depth of this book that the reader is able to follow detailed arguments about language design. Fascinating stuff.
The next two chapters, however, were my favorites. Effective Generics and Design Patterns give sensible, practical advice on using generics in your work, including the best explanation of <X extends Foo<X>> I've seen yet (so if you don't know what I am talking about here, read the book).
(A practical word of advice — if at all possible, use Java 6 with generics. Java 5 has a sneaky bug).
The Collections part of the book was more along O'Reilly's `Nutshell' lines: the different chapters explore different collection types in detail. I must admit that at first I skipped this — it looked like API docs re-hashed to extend the size of the book.
Then I felt bad, because I was supposed to be reviewing this book (full disclosure: if you review a book for Slashdot you get to keep it). And you know what? It turned out to be pretty interesting. I've programmed in Java for (too many) years, and I guess I've not been quite as dedicated to tracking how the library has changed as I should have been — I learned a lot.
Again, a wide range of readers are welcome. This is more than a summary of the Javadocs, ranging from thumbnail sketches of trees and hashtables to a discussion of containers intended for multi-threaded programming.
The way I see it now, this part is a bonus: the first half, on generics, makes this book one of the standards; the second half is an extra treat I'm glad I stumbled across (I guess if you're some kind of weird collection-fetishist maybe it's even worth buying the book for).
I've used generics since the first beta release of Java 5 and had experience with parametric polymorphism in functional languages before that (in other words, I can tell my co- from my contra-variance). So I guess I'm heading towards the more expert end of the spectrum and I was worried I'd find the book boring. It wasn't. After claiming to be expert I don't want to spoil things with evidence that I'm actually stupid, but reading this book cleared up a few `misunderstandings' I'd had. I wish I had read it earlier.
If you're new to generics, and you don't mind thinking, I recommend this book. If you're a Java programmer who's a bit confused by <? super Foo> then this is the book for you.
The only people who shouldn't read this are people new to Java. You need to go elsewhere first. This is not a book for complete beginners. This is a great book in the classic — practical, concise and intelligent — O'Reilly mould.
You can purchase Java Generics and Collections from amazon.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
Java generics are not real generics, then you parametrize a generic class in Java you don't really create a new type. You just attach some information for Java compiler so it can perform automatic casting and save you some typing.
Java generics don't provide real type safety, for example, you can easily put Strings in List (that's why Collections.checkedCollection kludge was added).
In C# (or C++), on the other hand, parameterizing a generic type creates a _new_ _type_ which guarantees type safety and allows some quite interesting tricks. For example, in C# generics can be parametrized by primitive types and structs (which don't exist in Java, anyway) so you can have List without overhead of boxing. That's impossible in Java.
Amongst those changes (enumerations, auto-boxing, foreach, varargs) generics was the most far-reaching, introducing generic programming in a simpler, safer way than C++ templates and, unlike generics in C#, maintaining backwards (and forwards) compatibility with existing Java code.
Yeah, and by maintaining that backwards compatibility, they became totally worthless.
The only thing it offers is some compile-time sanity checking, but even that can be disabled through use of a new compiler pragma directive to suppress warnings. In fact, in several cases, you HAVE to disable warnings because certain operations (like creating an array of a generic type) are impossible without a warning.
Ever wondered why the collection classes require you to pass in an array to the toArray(T[]) method? Because Java generics throw away the class information after compile time (although there's no reason they need to do this, they could have kept it and maintained backwards compatibility), so you have to pass in an array to give the type information Java removed.
Java generics could have been useful, but since casting them into a non-generic type generates an ignorable warning, they become worthless. It's only a few lines of code to place a Double into an Integer collection, thereby removing then entire point completely.
Unworkable. Polymorphism and ifs/switches are SEVERAL ORDERS OF MAGNITUDE faster than database access. So it's better to keep them separated.
Q uery for an example.
As for metaprogramming - you can look at Nemerle (http://nemerle.org/Main_Page) which excels at metaprogramming. It's one of the best languages I've seen.
But there's research in bridging the gap between databases and code - see http://en.wikipedia.org/wiki/Language_Integrated_
The language feature of generics *is* new. The compiler can still compile Java 1.1 source and can even compile to older class file versions. The generics implementation is for compile-time type checking, not runtime type checking. The compiled class file has no knowledge of generics.
Java generics are kept back-compatible with the old VM spec by way of type erasure: parametric information is "erased" from the type when it is compiled. So List and List and List all compile down to the same type: List.
Among other hiccups this makes it impossible to overload methods whose argument types differ only in the parametric information included with them.
By contrast, C++ templates and C# generics create a type disjoint from all other types in the same type class for each set of parameters in the type declaration.
Yet another sterling example of Java lossage.
N4st0r, trixx0r h0bb1tz0rz! Th3y st0l3 0ur pr3c10uzz!
Sentence in the above post should have read as follows:
So List<String> and List<java.math.BigInteger> and List<javax.swing.JComponent> all compile down to the same type: List.
N4st0r, trixx0r h0bb1tz0rz! Th3y st0l3 0ur pr3c10uzz!
*prepares to be modded troll*
People need to stop comparing Java/C# generics to C++ templates - they take similar syntax, but they aren't the same thing. I'm not sure how one can even be safer than the other.
And C# 2.0 maintained compatibility with existing C# 1.0 code (you still have access to the old containers) while actually giving significant performance benefits where Java is only syntax sugar that still produces the same old slow code.
Naftalin and Wadler are also holding a Java One session this year, it is on Wednesday, session id is TS-2890. If you have a Sun Developer Connection account (free) you can watch it online after the conference is over.
I agree with reviewer, the book is very good. It is true that Java generics is a compile time check, and that the generics information is removed (erasure). Nevertheless, that was a deliberate tradeoff for backwards compatibility, and it still makes coding complex Java a lot safer and easier. Look for instance at the 1.5 and 1.6 improvements to the concurrency libraries with Future, Callable and Executors.
Being bitter is drinking poison and hoping someone else will die
As soon as you use a generic, the Java compiler requires -source 1.5 and -source 1.5 requires -target 1.5 or higher. So -target 1.4 won't work, even though theoretically generics needn't require 1.5 binaries as all the checking is done at compile-time.
You are in a maze of twisty little relative jumps, all alike.
> If your code uses Java 5 features then it won't run on JDK1.4.
Your wrong. Or at least when it comes to Generics (I haven't tested the rest). Everything is done at the compiler level. So even if you use Generics the code is changed to work in 1.4 if you set javac -target 1.4.
Do the guys at SUN have such feature envy of C# (the bastard child of Java), that they can't just say enough is enough?
Sun does not control the development of Java, the Java Community Process does. And it is not C# that is seen as a threat I believe, but Ruby and functional languages. There is a VERY heated debate in the Java community over the new language features that are proposed for the Java platform, and both sides put up some very convincing arguments (simplicity is good vs a language needs to evolve, for instance). See for instance the different Closures proposals...
Being bitter is drinking poison and hoping someone else will die
Yes it is. ArrayList is a much better choice nowadays.
"The problem with internet quotations is that many are not genuine" -Abraham Lincoln
Utter BS. I worked for a couple of years developing Win32 apps. We supported everything from 95 through to XP and I can assure you that there is NO FUCKING WAY that the OS runs the old binaries flawlessly!
The code is riddled with conditional paths for different OS versions. Testing across windows versions was a nightmare.
I suggest it's you who is being criminally thick.
Meaning that if you ever plan to do anything with threads, stick with Vector.
Actually, no. Use ArrayList and synchronize access to it where needed in your code. The synchronization in Vector is a very blunt tool.
The Problem is that the synchronization is applied at the method level. That means there's nothing to stop invocations of different methods from both attempting to update the same data inside the vector at the same time, which can cause bugs that are almost impossible to track down.
The GP was correct...if you need synchronization, use and array list and either declare it to be synchronized or access it within a synchronized block. The Vector and Hashtable classes really have no place in code that doesn't need to compile under ancient versions of Java.
"Don't blame me, I voted for Kodos!"
-
disable language unsupported features (generics, assertions can be compiled within a certain degree - enumerations can't) ;
-
compile against the libraries version of the target VM, otherwise even if the class files remain compatible, there may be calls to non-existent methods) ;
- ensure yourself that all of your libraries will be compatible with that VM version (not as straightforward as it sounds)
- Perform tests against the VM you're targeting, and if it's a desktop distributable application, against all VMs that came after that version
;
- ??? I forgot.
In fact, in most projects that target an obsolete VM, it's much, much easier to get yourself the compiler for that VM, and code only on it. As an example, I'm currently running Eclipse on Java 6 VM, but since most work is still done on Java 1.4, or even 1.3, I keep most of those JDKs on my hard-drive..... In fact, I think this is one of the main reasons many people still code on Java 1.4 (as opposed to a MS pure environment, where most C# 1.2 projects translated into C# 2.0 when it appeared 2 years ago), even if it's really hard to imagine otherwise.... Sun could really have done a lot more to encourage Java development.I believe the GP was talking about this problem, with reading and writing the Vector at the same time (not writing from two threads). Which is not threadsafe.
ustr: Managed string API with ave. 44% overhead over strdup(), for 0-20B