I've been a zone leader with DZone since 2008, and I'm crazy about community. Every day I get to work with the best that JavaScript, HTML5, Android and iOS has to offer, creating apps that truly make at difference, as principal front-end architect at Avego. James is a DZone Zone Leader and has posted 639 posts at DZone. You can read more from them at their website. View Full User Profile

Effective Java: An Interview with Joshua Bloch

05.22.2008
| 25061 views |
  • submit to reddit

The most anticipated book among Java developers over the past few years has been the second edition of Effective Java by Joshua Bloch. The book was finally launched during JavaONE this year. I caught up with Josh and discussed the book, the changes in industry since the last edition and his thoughts on closures.

Want a signed copy of Effective Java? Subscribe to DZone Refcardz and be automatically entered into our competition to win one of three copies exclusively for DZone members.

James Sugrue: The book was made available at JavaONE. Did you do any technical sessions to coincide with the release?

Joshua Bloch: I did two sessions. On was directly related to the book. It was called "More Effective Java." It was largely devoted to enum types (Items 30-34, 77), but also included a mnemonic for the use of bounded wildcard types (Item 28) and a guide to lazy initialization (Item 71).

Sugrue: What changes have been added to bring to book up to date?

Bloch: I added two chapters, one on Generics, and another on Enums and Annotations. Also I added items describing best practices for each of the new language features in Java 5 (for-each loop, autoboxing, varargs, static import). I changed the title of the Threads chapter to Concurrency and rewrote it to reflect programming in the java.util.concurrent era (where the basic abstractions are tasks and executors, rather than threads, wait and notify). There's a table on page 1 that points you to all of this material.

In addition to adding material on features that were added to the platform since the first edition of the book, I added items or modified existing ones to reflect the evolution of best practices. For example, I added an item describing the Builder pattern (Item 2), and one describing the Serialization Proxy pattern (Item 78). I went over every line of every item, and did my best to make sure they were up to date.

Sugrue: Is it fair to consider this as a whole new book?

Bloch: No! I did my best not to change the character of the work. I hope it feels like an old friend to readers of the first edition.


Sugrue: Since the first book in 2001, what key changes have you observed in Java development?

Bloch: The biggest changes are the rise of modern IDEs, such as Eclipse, IntelliJ, and NetBeans, and static analysis tools, such as FindBugs. Agile techniques, which were just making inroads in 2001, have become mainstream.

Sugrue: Effective Java is seen as one of the most important books for Java. Considering it's popularity, were you wary of making any changes to such a well established book?

Bloch: Very much so. That's why I tried so hard not to change the character of the book. Of course I had to cover all of the new material, and I had to critically examine everything I said in the first edition. But I did everything in my power to make sure that nothing got hurt in the process. I hope I succeeded, but I won't know for sure until I've heard from readers of the second edition.

Sugrue: Every developer should read this book - but some might not be able to make time. For those, if you were to promote just one message from the book what would it be?

Bloch: I was asked the same question the very first time I was interviewed about Effective Java, back in June 2001. This is what I replied: Always strive to write simple, clear, and correct programs. It is penny wise and pound foolish to do otherwise. Style does matter. It pays real dividends in terms of correctness, usability, robustness, and maintainability. Also, it's way more fun to write good programs than bad ones.

I still believe every word.

Sugrue: What is the most common fault in Java developers in your opinion?

Bloch: Like most programmers, we have a natural tendency to optimize our code even when we should know better. Our attempted optimizations don't always make the code run faster. Sometimes they just make it more complicated.

Sugrue: The book includes hints for class and interface design. In one paragraph, can you describe a guideline for a good design?

Bloch: I apologize if this sounds trite, but each class should do one thing, and do it well. There's a great litmus test: can you, in one short, clear noun phrase, describe what an instance of the class represents? If not, you should probably spend more time thinking about the design.

Sugrue: Scripting on top of the JVM has become very popular over the past year or so. What do you think of it?

Bloch: I'm a pragmatist. Often it's the easy way to get things done, and that makes it good. Of course you should write your scripts with all the care that you write your programs, because they'll have to be maintained in parallel with the programs.


Sugrue: What is your opinion on the inclusion Closures in Java 7?

Bloch: As readers of the first edition know, I value simplicity and clarity above all else. So it should come as no surprise that I don't want to see anymore major additions to the Java programming language. It's already as complex as a language should be. If Java programmers want to use features that aren't present in the language, I think they're probably best off using another langauge that targets the JVM, such a Scala and Groovy.

Sugrue: To Java developers your book is seen as a bible. Can you recommend any other books to sit alongside yours on the developer's bookshelf?

Bloch: Sure. For concurrency, I recommend Java Concurrency in Practice by Goetz, Peierls, et al. For bit twiddling, go with Hacker's Delight, by Henry S. Warren. A couple of classics that only improve with age are Frederic P. Brooks's The Mythical Man Month, and Jon Bentley's Programming Pearls. And every programmer should read Strunk and White's The Elements of Style. Not only will it make you a better writer (which is an important part of being a software engineer) but it will make you a better programmer. Programming and writing have a lot in common: both are about expressing yourself clearly and concisely.

Comments

Geertjan Wielenga replied on Thu, 2008/05/22 - 4:29am

[quote]As readers of the first edition know, I value simplicity and clarity above all else. So it should come as no surprise that I don't want to see anymore major additions to the Java programming language. It's already as complex as a language should be. If Java programmers want to use features that aren't present in the language, I think they're probably best off using another langauge that targets the JVM, such a Scala and Groovy.[/quote]

+1. I think that more people who hold this view should come forward, because at the moment the main discussion seems to be "which of the various Closures proposals should be included in Java 7?" Seems to me that the "let's not clutter Java" (LNCJ) camp has been too quiet. Maybe because Neal Gafter et al are pretty authoratative voices? Well, the LNCJ camp includes Josh Bloch, so that can't be bad...

Jesper Nordenberg replied on Thu, 2008/05/22 - 6:00am

I agree that Sun shouldn't add to much stuff that doesn't fit well into to the Java language. Leave Java as it is and focus efforts on a modern, statically typed, Java-compatible language for the JVM. Scala is the best alternative right now, but it could use some backing from Sun, similar to how they support Ruby. Especially the IDE support needs to be improved.

There are some fundamental things that needs to be improved in the Java language and the JVM:

  • primitives should be removed (ie the way it's done in Scala)
  • type erasure sucks, add proper runtime support for generic types in the JVM like MS has in .NET
  • higher order functions/methods are a fundamental building block in all modern programming languages and they should be used a lot in the runtime libraries
  • traits/mixins should be supported, Scala has to work around this limitation in the JVM and that introduces unnecessary binary incompatibility issues
  • some support for easily creating immutable classes (Scala has case classes)

There are probably more issues, but that should keep Sun employees busy for a while :)

Alexander Grünewald replied on Thu, 2008/05/22 - 7:58am

I played with Mr. Gafters Closure prototype and it was an awesome experience. Now I do often see code where I think, it would be much easier if I could use closures here. I could write the same thing in a much simpler and clearer way.

PS: I would also add "Java Puzzlers" to the list of Java books that are much fun to read.

Ricky Clarkson replied on Thu, 2008/05/22 - 8:05am

"I value simplicity and clarity above all else. So it should come as no surprise that I don't want to see anymore major additions to the Java programming language."

Hang on, I don't get this.  Major additions don't have to be the opposite of simplicity and clarity.  When Josh's own feature made it into Java, enums, Java gained simplicity.  And all three terms (major, simple, clear) are ambiguous.  I can twist them in my own ways too.  Here, I'll have a go: "Let's not, um, add 'BigInteger+BigInteger' support to Java, because it's such a major change, and goes against the clarity and simplicity of the Java programming language".

Also, as Groovy's grammar is an extension of Java's(*), I have no idea why Josh is pointing people at Groovy for closure use.  If Groovy can have all Java's grammar and add closures, with Josh's support, why can Java not benefit the same way?  Putting my cynical head on, I'd say that Josh is trying to distract us.  If you want closures in Java.. "look, a pink elephant!".

* I have no intention of promoting Groovy here; Groovy's grammar is an extension of Java's, but the code actually means different things.  int i="hello"; is valid Groovy code, for example.  At least I can agree with Josh when he suggests looking at Scala, but I think we have different reasons.

Jesper Nordenberg replied on Thu, 2008/05/22 - 9:39am

The problem is that it's not so easy to introduce closures in Java at this stage. Joshua gave a talk a while back where he described the pitfalls of current implementation proposals. If it can be added without too much developer confusion/pitfalls, it might be a good addition to the language. But, IMHO, the effort should be directed towards creating a modern "Java" instead which is designed from the ground up to support closures/higher order functions and other modern language constructs. Sun is spending too much resources extending Java and creating buzz word technologies like JavaFX. The JVM is a great platform, let's improve it and design a language for the future instead of patching an old, stable one.

Java generics was implemented in a very bad way (erasure) and that lead to lots of confusion in the Java world (the generics FAQ is HUGE). Let's not repeat this mistake again. 

Honey Monster replied on Thu, 2008/05/22 - 10:52am in response to: Jesper Nordenberg

[quote=jn45229]Joshua gave a talk a while back where he described the pitfalls of current implementation proposals. If it can be added without too much developer confusion/pitfalls, it might be a good addition to the language.[/quote]

And that is the problem with BGGA: It tries to solve two problems: Introducing the much needed closures and allowing new progranner-defined control blocks, such as the C# using statement. While somewhat related (the content of a control block can be viewed as a closure) the linking of the two concepts are by no means a given. Control blocks could be achieved through some other means, such as programmable syntax macros.

The linking of these two concepts in BGGA is exactly what creates the need for some very foreign Java syntax and semantics: Suddently a return statement cannot be used to escape the current block, because if it is to be used inside a control block return must be reserved to return from the outer block. Hence, instead of using a familar syntax for return values (as in C# closures) BGGA introduces a new way to return a value from a block, completely different from the way Java developers would return values from the block of a regular method.

While control blocks would be nice, this entire process has an unsettling resemblance to what happened to Java generics: A niche concern was allowed to dominate the proposal, completely skewing and undermining the primary purpose to the point where generics are sub standard.

[quote=jn45229]Java generics was implemented in a very bad way (erasure) and that lead to lots of confusion in the Java world (the generics FAQ is HUGE). Let's not repeat this mistake again.[/quote]

I completely agree. What most developers want is simply closures. I don't believe that many developers need to create control blocks themselves. It is a niche concern, and by the looks of it history is about to repeat itself.

John O'Hanley replied on Thu, 2008/05/22 - 11:30am

Looking forward to reading the 2nd edition. The first edition was very beneficial for the Java community, and a pleasure to read...

- John

Augusto Sellhorn replied on Thu, 2008/05/22 - 1:52pm

Continue extending Java?

My answer, from a year ago;

http://sellmic.com/blog/2007/01/26/evolution-is-good/

And I agree with a previous comment, things like enums simplify the language. Changing languages to seek features like that seems like a waste of resources. In the real world, you don't tell your customer or client, hey we're switching to language X tomorrow just because you want to simplify development a bit.

Ricky Clarkson replied on Fri, 2008/05/23 - 5:56am in response to: Jesper Nordenberg

It is pretty easy to introduce closures at this stage.  Gafter's BGGA prototype shows this.  The few items that were about syntax in Josh's talk have since been addressed in the BGGA prototype.

Sun spending resources?  It looks to me like they're quite happy for 3rd parties like Gafter to do it for free.

I don't see how generics are relevant.  Sun's compiler staff is quite different now to how it was then, and the process is more open.  I daresay that if today's Java didn't include generics already, it would be hard to add generics in the form they were added.  That said, erasure isn't definitely a mistake - it's nice that generics doesn't cost us anything at runtime.  It's just pretty annoying that they didn't include any features for reification in the places that it's needed (interaction with arrays, etc.).  And varargs using arrays just seems like a miscommunication.

Jess Holle replied on Fri, 2008/05/23 - 7:15am

Type erasure was not a mistake -- it's the only thing allowing me to use generics today, and I use them a lot.

Type erasure is what allows me to use fully generified collections in new code and pass them to and from old code which I don't have source code to or rights to modify or which there simply is no time to modify.

Perhaps Sun could have solved this issues without type erasure, but every proposal I've heard contains one of two ugly notions:

  1. Have 2 collections (etc) packages, one with type info and one without
  2. Have 2 different ways of declaring instances of a generic type, one with type info and one without

(1) is a non-starter as far as I'm concerned.  It's what C# did, but ... yuck!  (2) would be complex and those working with large systems containing old code would never get to use the "with type info" option, but it could work.  I'm not sure it is worthwhile overall, though.

I'd be all for keeping generic type info around on an instance level (e.g. accessible via getTypeInfo() or some such ala getClass()) when possible and even having certain language features (e.g. new T()) implicitly use it and produce runtime errors when it is not present.  Having the JDK use these latter features and thus kill interoperability with old code is somewhat of a non-starter, though.

I'm more unhappy with the lack of appropriate compile-time generic type inference in numerous cases and the stupid array type handling.  [If I can declare generic types using array types but can't instantiate them but can instantiate a similar type and caste it to use the array types I originally wanted, then something is wrong.]

Jess Holle replied on Fri, 2008/05/23 - 7:22am

I like the KISS principle for Java overall, but remain torn on closures.

I do think attempts to turn everything into a DSL are short-sighted.  Java code should look like Java.  It should be clear what's going on, what's a method call on what, what's a language keyword and what's not, etc -- all when looking at source in an e-mail or such, without a super-duper IDE.  Trying to make segments of the code look like an entirely different language throws overall program comprehension out the window.  So this is a definitive non-goal -- and danger -- with closures (at least BGGA style) as I see it.

Traits on the other hand should have been in Java years ago.  The lack of at least this limited form of multiple inheritance has required stupid workaround, unnecessary boilerplate delegation, etc, that should have been identified and rectified rather than accepted.  [I'd actually prefer full-blown multiple inheritance, but I believe it is truly too late for that to be added.]

Jesper Nordenberg replied on Fri, 2008/05/23 - 8:27am

My opinion is that if you're going to do something, do it all the way and not some half-baked solution. It may seem like the cheapest solution at the moment, but you're gonna pay the price later. The price payed for type erasure is work arounds and confused developers, which IMO is much higher than writing a few wrapper classes for collections.

> That said, erasure isn't definitely a mistake - it's nice that generics doesn't cost us anything at runtime.

Do you mean that it's good that there is no runtime type information? Or that a list of integers wastes a lot of memory and need boxing/unboxing to work?

 

 

 

 

Ricky Clarkson replied on Fri, 2008/05/23 - 10:02am

It's good that there's no runtime type information when you don't need it.  I did say that it would have been good if they'd included features for reification when you do need it.

A List of Integers having boxing overhead over an array of ints is not related to reification.

Jesper Nordenberg replied on Fri, 2008/05/23 - 10:24am in response to: Ricky Clarkson

[quote=rickyclarkson]

It's good that there's no runtime type information when you don't need it. I did say that it would have been good if they'd included features for reification when you do need it.

[/quote]

I still don't get what you're saying. In what way does, for example .NET generics, have a higher runtime cost than Java generics?

[quote=rickyclarkson]

A List of Integers having boxing overhead over an array of ints is not related to reification.

[/quote]

No, but it definitely introduces a runtime cost.

Ricky Clarkson replied on Fri, 2008/05/23 - 10:54am

"what way does, for example .NET generics, have a higher runtime cost than Java generics?"

Each generic list in .NET has an extra token, something like a Java class object.  It isn't normally checked when list.Add is called, as far as I can tell, because it doesn't need to be; it's statically checked.  It's a constant overhead, but certainly an overhead in memory.

"No, but it [boxing] definitely introduces a runtime cost."

I completely fail to see how this situation differs from Java 1.4.  In Java 1.4 to put ints in a List you would call Integer.valueOf(int).  Now you get the same without the explicit call.  The performance is identical.

 

Honey Monster replied on Fri, 2008/05/23 - 2:38pm in response to: Jess Holle

[quote=jessh]Type erasure is what allows me to use fully generified collections in new code and pass them to and from old code which I don't have source code to or rights to modify or which there simply is no time to modify.

Perhaps Sun could have solved this issues without type erasure, but every proposal I've heard contains one of two ugly notions:

  1. Have 2 collections (etc) packages, one with type info and one without
  2. Have 2 different ways of declaring instances of a generic type, one with type info and one without

(1) is a non-starter as far as I'm concerned.  It's what C# did, but ... yuck![/quote]

I think you are mistaken. Check out the definition for List<T> of .NET:

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable

Explanation: C# indeed introduced new type-safe collection types instead of extending the old ones. Thus removing the need for type erasure. But as you can see from the definition, .NET lists still implement the "old" untyped collection interfaces (IList, ICollection, IEnumerable). Thus, a C# programmer is free to pass a list to code which expects untyped lists. The generic implementation of the untyped IList methods performs the required typecasts.

It is a bit ironic, because the Java collections were always much better abstracted (using good interfaces) than the .NET ones (which I to this day believe was written by an intern who had never seen Java nor C++ STL).

Jesper Nordenberg replied on Fri, 2008/05/23 - 2:45pm in response to: Ricky Clarkson

[quote=rickyclarkson]

"what way does, for example .NET generics, have a higher runtime cost than Java generics?"

Each generic list in .NET has an extra token, something like a Java class object. It isn't normally checked when list.Add is called, as far as I can tell, because it doesn't need to be; it's statically checked. It's a constant overhead, but certainly an overhead in memory.

[/quote]

I don't see why this couldn't be stored in some generic class instantiation information block. That would mean there would be some overhead for each unique instantiation (not each object), but that would be negligable compared to other class information.

 [quote=rickyclarkson]

"No, but it [boxing] definitely introduces a runtime cost."

I completely fail to see how this situation differs from Java 1.4. In Java 1.4 to put ints in a List you would call Integer.valueOf(int). Now you get the same without the explicit call. The performance is identical.

[/quote]

The VM can specialize generic class instantiations for primitives (if I'm not mistaken .NET VM does this) which means that a list of integers can use an int[] instead of a Integer[] as backend. The (un)boxing overhead is not that big, but the memory overhead can be quite substantial.

Honey Monster replied on Fri, 2008/05/23 - 2:53pm in response to: Ricky Clarkson

[quote=rickyclarkson]

"what way does, for example .NET generics, have a higher runtime cost than Java generics?"

Each generic list in .NET has an extra token, something like a Java class object.  It isn't normally checked when list.Add is called, as far as I can tell, because it doesn't need to be; it's statically checked.  It's a constant overhead, but certainly an overhead in memory.[/quote]

I'm not sure I understand you here. .NET generics are integrated in the type; it's just an extension of the type system. An instance of a parameterized type simply has a type pointer as they always had. No extra overhead. Because .NET does not use type erasure, List<string> if a different type from List<Object>. The .NET class loader verifies the code at load/JIT time. .NET generic classes therefore hava less runtime overhead compared to Java generics which must perform typecasts at runtime. Furthermore .NET allows primitive types/value types such as int and double to be used as generic parameters. This also avoids the (considerable) overhead of boxing/unboxing when using e.g. collections of primitive types.

Ayodeji Aladejebi replied on Sun, 2008/05/25 - 3:17am

For generics, i remember at the early stage before i learnt about Type Erasure running into a situation like this:


interface Loveable<T>{

T showMeYourType(T t);

}

This is a simple typical interface. Now for you to do this during an implementation:

 

class LoverBoy implements Loveable<Tall>, Loveable<Dark>, Loveable<Handsome>{
}

Now obviously I got a compiler error. Oh!, we cant do that? then I got the message on limitations of Generics

George Jiang replied on Mon, 2008/05/26 - 12:35am in response to: Honey Monster

Now can anyone else tell why (1) is a non-starter? Otherwise it only shows that Java 5.0 engineers made a much worse decision than their C#3.0 counterparts.

Jesper Nordenberg replied on Mon, 2008/05/26 - 5:31am in response to: Ayodeji Aladejebi

[quote=xane]

This is a simple typical interface. Now for you to do this during an implementation:

class LoverBoy implements Loveable<Tall>, Loveable<Dark>, Loveable<Handsome>{
}

Now obviously I got a compiler error. Oh!, we cant do that? then I got the message on limitations of Generics

[/quote]

Hehe, you actually wrote this code when you tried generics the first time? :)

Anyway, it's one of the things that sucks with type erasure. 

[quote=george.jiang]

Now can anyone else tell why (1) is a non-starter? Otherwise it only shows that Java 5.0 engineers made a much worse decision than their C#3.0 counterparts.

[/quote]

I don't know what a "non-starter" is, but I do think MS implemented generics in a much better way than Sun. I can't really say why Sun chose the type erasure way, maybe cause they thought modifying the JVM to support proper generics would be a too big effort. I guess they took the easy way out.

Ayodeji Aladejebi replied on Mon, 2008/05/26 - 6:10am in response to: Jesper Nordenberg

believe me , I started writing Java since Java1.2 and I have really learnt a lot about interfaces over years of using Java and why they should be prefered in design challenges thanks to Josh Blochs book. So generics was recieved with open arms. After seeing many examples of Generics, I actually thot that was possible. Obviously I was wrong

George Jiang replied on Tue, 2008/05/27 - 4:52am

As C# 2.0 generics came out first, it might be Sun desired to do things differently from Microsoft :-)

George Jiang replied on Tue, 2008/05/27 - 4:58am in response to: Jesper Nordenberg

As C# 2.0 generics came out first, it might be Sun desired to do things differently from Microsoft :-)

Carla Brian replied on Wed, 2012/05/30 - 11:19am

This is interesting. I love their conversation. I learned many things through this. - James P Stuckey

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.