|
|
|||||
Graham Hamilton's BlogNovember 2005 ArchivesI'm Looking for some Java BoilerplatePosted by kgh on November 15, 2005 at 06:18 AM | Permalink | Comments (47)We know we have a lot of power in the Java platform, but sometimes that power has come at a cost in simplicity. We want to improve that, and Ease-of-Development has been a major focus of Tiger, Mustang and Java EE 5. Sometimes we need to add major new features to simplify life for developers but often the problem isn't that there is missing functionality, but that the existing functionality is cumbersome to use, or requires typing unnecessary boilerplate code. To give you a sense of the kinds of things I'm talking about, see My Favorite (Dead) Java Boilerplate. That gives five examples of removing rough edges and simplifying common tasks. We've accomplished a lot already, specially in Tiger and in Java EE 5. But I think there is still more to do and I am looking for the next set of things we ought to try to simplify or eliminate. You can help. What are your favorite Java annoyances? I'm particularly looking for areas where people regularly have to type in awkward or redundant code that ought to be eliminated. In this context, I am mostly not looking for big language changes or major framework proposals. (We tend to do quite enough of that already!) I'm hunting for the smaller polishings that often get overlooked. (Many thanks to people who've already posted suggestions!) If you have other suggestions, send an email describing the problem to java-boilerplate@sun.com. We probably won't be able to respond to individual suggestions, but we will read all the proposals carefully. Note: you don't need to provide a solution. If we can clearly identify the problems we have a large toolbag to attack them with. This is your chance to help get your favorite rough edges fixed!
My Favorite (Dead) Java BoilerplatePosted by kgh on November 13, 2005 at 04:03 PM | Permalink | Comments (31)In the Java platform we have tended to focus on adding lots of power and flexibility. That's great, but sometimes that power and flexibility can get in the way of doing common tasks. As part of the Ease-of-Development initiative we have been focusing on simplifying common tasks and getting rid of unnecessary boilerplate code. Here are my five of my favorite cleanups so far: #1: Opening a Text File In JDK 1.1 to 1.4, in order to open a simple text output file you needed to do: FileWriter fout = new FileWriter("fred.txt");
BufferedWriter bout = new BufferedWriter(fout);
PrintWriter pout = new PrintWriter(bout);
Say what? Why are we having to type three "new"s in order to do what should be a simple operation? In Tiger we have finally added direct support for the common case and now you can do: PrintWriter pout = new PrintWriter("fred.txt");
This is an interesting example of a common glitch in our thinking. In the Java platform we often like to provide lots of well designed, well separated components that can be plugged together in interesting ways. In fact some people might argue be that the design is cleaner if the PrintWriter class doesn't know anything about files. Well, personally, I don't think so. I think it is good to provide clean, well separated components, but we also need to provide simple shortcuts to support the most common use cases. #2: Avoiding the Content Pane Pain In JDK 1.1 to 1.4, if you wanted to add a Swing GUI component to a container you simply said container.add(component). Well, yes, except that if the container happened to be a JFrame you would get a helpful runtime exception saying that you ought to be saying frame.getContentPane().add(component); Umm, say what? Rather than raising the exception, couldn't the JFrame.add method itself call JFrame.getContentPane().add()? Yes it could. And in Tiger it does. Now you can just call add, as you would with any other container object. frame.add(component); This only saves a few keystrokes, so is this really a big deal? Yes. The real saving is that you can avoid having to learn a whole new unnecessary concept. The reason that the JFrame.add method originally threw an exception was because JFrames actually support three different panes (content, glass and root), and it was considered important to educate developers about those choices. Well, I've written various Swing applications over the years and I've never actually found the need to exploit the various different panes. The old behavior of JFrame.add forced me to go away and learn about panes. And that was distracting and unhelpful. The lesson here is that (once again) it is normally better to provide simple sensible defaults and to avoid forcing people to learn about complex options. #3: Self Registering JDBC Drivers Since JDK 1.1, in order to load a JDBC driver, you needed to do: Class.forName("com.fred.FredDriver");
Connection con = DriverManager.getConnection("jdbc:fred:fredsite.com");
Umm, what exactly is that Class.forName doing there?
This one is my fault. Back in the early days of JDBC, we needed a way
for the JDBC DriverManager to locate drivers. We arranged that newly
loaded driver classes would register with the
DriverManager. And then we asked that developers call
"Class.forName" to force the driver class to be loaded.
Sigh. This is an ugly wart. I'm happy to report that this one is going away as part of JDBC 4.0 in Mustang. The JSR-221 Expert Group is adding a new mechanism so that the JDBC DriverManager can locate and load driver classes without the need for developers to explicitly type Class.forName. So you will be able to just do the obvious: Connection con = DriverManager.getConnection("jdbc:fred:fredsite.com");
#4: Locating Resources in J2EE In J2EE 1.4, if you wanted to locate a reference to a remote EJB you needed to type: Context context = new InitialContext();
Object obj = context.lookup("fred");
FredHome fred = (FredHome) PortableRemoteObject.narrow(obj, FredHome.class);
Yikes. What on earth is going on with that PortableRemoteObject.narrow? I have to confess that I'm one of the prime culprits here and, given some of the constraints, it may have been unavoidable. But I think this one definitely does win "Ugly Boilerplate of the Year". As part of Java EE 5, there are now specific mechanisms for dependency injection, so you can now replace that code with a simple annotated field definition: @Resource FredHome fred; And then the Java EE runtimes will take care of locating the resource, doing the "narrow" for you and injecting the resource object into your field. By default the resource name is inferred from the field name and the type is inferred from the field type. This is an example of using JSR-175 annotations to restructure how we handle a common task so that it can become much simpler. I'm very excited with what is happening with annotations as part of Java EE 5 - I think it is allowing us to greatly simplify Java EE programming. And I'd like to find more ways to use annotations in Java SE, too. #5: Iterating over Collections My last example is from Tiger. We've all been used to typing some standard boilerplate for iterating over collections, such as: Vector<Wombat> v = getWombats();
Enumeration<Wombat> e = v.elements();
while (e.hasMoreElements()) {
Wombat w = e.nextElement();
...
}
Josh Bloch successfully argued for a language change to make it easier to iterate over both collections and arrays, so now in Tiger we can do: Vector<Wombat> v = getWombats();
for (Wombat w : v) {
...
}
We all knew this would be useful, but I have been really surprised by how much I have enjoyed using it, for both arrays and collections. This has turned into one of my favorite Tiger features. The resulting code is distinctly easier to read, partly because we have managed to eliminate an unnecessary local variable. This is an example of fixing a boilerplate problem we barely realized we had. I'd like to find a few more things like this! To be continued... I'll continue this topic in my next blog.
| |||||
|
|