ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button
Java Cookbook, 2nd Edition

Keeping Up with the Java Joneses

by Ian F. Darwin, author of Java Cookbook, 2nd Edition
07/28/2004

What's new? That's a loaded question. Back in the days of Java 1.0 and 1.1, a Java geek could comfortably claim to "know all about Java." By the time of 1.2, that claim was manifest nonsense. By the time of 1.3 or 1.4, James Gosling started recommending other Java books that he wished he'd seen years earlier. Now that 1.5 is here, if someone says they know all about Java, forget it.

So what's new, really? J2SE 1.4 introduced a variety of technologies, such as a standardized Java implementation of regular expressions (see Chapter 4 of the Java Cookbook, 2nd Edition). J2SE 1.5 introduces lots more. One of the most notable sets of additions is "generic types," such as collections, that are defined to hold objects of a certain type rather than just Object (obviating the downcast otherwise needed each time you get an object back from a collection), built-in support for typesafe enumerations, and an extended for loop to iterate over collections. For example, with a List of Strings, prior to 1.5 you might write:

	List myList = new ArrayList();
	myList.add("hello");
	myList.add("goodbye");

	// myList.add(new Date()); This would compile but cause failures later

	Iterator it = myList.iterator();
	while (it.hasNext()) {
			String s = (String)it.next();
			System.out.println(s);
	}

In 1.5 you can write this as:

	List<String> myList = new ArrayList<String>();
	myList.add("hello");
	myList.add("goodbye");

	// myList.add(new Date()); This won't compile!

	Iterator<String> it = myList.iterator();
	while (it.hasNext()) {
			String s = it.next();	// Look Ma, no downcast!
			System.out.println(s);
	}

This mechanism is called "generics" because it allows you to write generic classes, the arguments and return types of methods of which are specified when the class is instantiated.

While the original definition of the List interface and the ArrayList class had methods dealing in java.lang.Objects, in 1.5 these types have been changed to a Generic type so that you can declare and instantiate them with any object type (String, Customer, Integer), and get the benefits of stronger type checking and elimination of downcasts.

Related Reading

Java Cookbook
By Ian F. Darwin

Not just these types, but all of the Collections API and most of the other parts of the standard Java API in 1.5 have been updated to be generic types. If you write your own multipurpose classes, you can fairly easily change them to be generics in the same fashion.

The notation <type> is used to specify the particular type with which the class is to be instantiated. Java developers had better get comfortable with this notation, as it is used extensively in the 1.5 JavaDoc!

These additions related to data structuring are all covered in Chapter 8 of my Java Cookbook, 2nd Edition; this chapter is online here.

So what else is new? Well, plenty more, it turns out. And not just in J2SE 1.5. The rest of this article covers a variety of new Java features, and ends with a wrap-up of ways to stay current on Java.

J2SE 1.5 Threading

Java was the first mainstream language with explicit support for multithreading. It has always been possible to write Java applications that run multiple sections of code more or less concurrently. In fact, even the simplest Java application creates at least one thread -- Java's memory allocation garbage collection runs in a background thread, started by the Java runtime before you can say "Hello World."

However, the code required has sometimes been slightly convoluted. In Java 1.5, the API has been significantly expanded to provide a series of utility classes that make it much easier to support multithreaded applications. Even such complex operations as various types of locking, and creation of thread pools, have been addressed. This work is an outgrowth of an open source library developed by Doug Lea, author of the book Concurrent Programming in Java and a computer science professor at State University of New York in Oswego, New York. This code was contributed to the Java Community Process where it has been extensively worked over by a multitasking committee of multithreading experts. The package java.util.concurrent and its subpackages contain all of the new classes, and there are quite a few of them.

One of the key differences from traditional Java synchronization is that the new classes really are concurrent. That is, while a synchronized class such as Vector or Hashtable uses the object's monitor lock to block all but a single thread from running any synchronized method at a time, the new concurrent classes will allow multiple threads to access them at the same time, yet still provide "thread-safe" access. For example, the new ConcurrentHashMap class allows an unlimited number of concurrent reading threads and a (settable) maximum number of writes. This will generally lead to much better scalability and faster performance, both of which become important when designing enterprise-scale application services. What's also nice about the ConcurrentHashMap is that, because it still implements the Map interface from java.util, it is a drop-in replacement for the older synchronized Hashtable class. So using it can be as simple as adding an import and changing:

Map myMap = new Hashtable();

to

Map myMap = new ConcurrentHashMap();

Of course, since you read the opening paragraphs, you'll know that you probably want to use it in a typesafe way, so if your Map were hashing from String to CustomerAddress object, you'd actually write:

Map<String,CustomerAddress> myMap = 
    new ConcurrentHashMap<String,CustomerAddress>();

I did say you have to get used to that <type> notation. Note that in 1.5, the Map interface is now declared as Map<K, V> (for Keys and Values); the iteration methods are declared in the interface as Enumeration<K> keys() and Collection<V> values(). So you would get Enumeration<String> keys() and Collection<CustomerAddress> values() from the "keys" and "values" methods, respectively.

Since you give the type for the keys and values when you instantiate a class implementing Map, you get back the iterators with the correct types built in, meaning no downcast needed when you extract the elements.

Getting the JDBC Out of Java

One of the funnier phrases used in Java web development is "getting the Java out of the JavaServer Pages" -- putting the Java into reusable components and also making the remaining HTML-like pages easier to maintain.

Hibernate and JDO are two alternative ways of storing data. They are two of a number of "object-relational mapping" packages that have surfaced in recent years to simplify, as the name implies, the mapping from objects to a relational database. It's been said that when all you have is a hammer, everything looks like a nail. Similarly, if all you have is JDBC, everything looks like, well, SQL. Hibernate and JDO let you think directly in terms of objects, instead of having to work through the "foreign language" of SQL.

Hibernate is an open source project, available free in source code form from hibernate.org. JDO is an open specification from the Java Community Process (jcp.org). There are many implementations of JDO, both free and commercial; you can find out about many of these at jdocentral.com.

In Java Cookbook, I felt I had to choose between JDO and Hibernate, so I used JDO in the examples there. To make up for that, I'll give an example of Hibernate, simplified for presentation purposes from a client-specific login module I wrote for XPlanner (a good tool for XP management, by the way).

import java.sql.SQLException;
import java.util.Date;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;

import demo.hibernate.ThreadSession;
import demo.domain.Person;
import demo.domain.RoleAssociation;

public class HiberDemo {
	private static final int ROLE_VIEWER = 0;

	public void addPerson() throws SQLException, HibernateException{
		Session sess = null; // Hibernate session, not Http, nor Mail, nor ...

		sess = ThreadSession.get();
		sess.beginTransaction();

		Person person = new Person();	

		person.setName("Some Name");
		person.setEmail("some_name@ersatz.dom");
		person.setPhone("555-555-5555");
		person.setPassword("this password is not used");
		person.setLastUpdateTime(new Date());
		
		sess.save(person); 
		
		//  group roles
		System.out.println("Person.id set to " + person.getId());
		sess.save(new RoleAssociation(0, person.getId(), ROLE_VIEWER));
		
		sess.flush();
		sess.connection().commit();
	}
}

What's interesting is the lack of SQL; the only import is for SQLException for the commit. Hibernate handles all of the details of the SQL, even to relationships between objects.

Of course, there is an XML file that describes the mapping from the fields of the Person class into columns of an SQL table. In fact, you can write this XML file and have Hibernate generate the Person class, if you like!

And there is also the usual properties file with such details as the JDBC URL and driver.

Hibernate, like JDO and like Entity EJB, provides a high-level, SQL-like query language, as well.

To learn the working details of Hibernate, please check out hibernate.org. There's a nice simple introduction online at systemmobile.com. Another resource is O'Reilly's recently released Hibernate: A Developer's Notebook.

Take a look at JDO and Hibernate, and you'll never view JDBC in quite the same light again.

Pages: 1, 2

Next Pagearrow