Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Introduction to Java programming, Part 2: Constructs for real-world applications

More-advanced Java language features

J Steven Perry, Principal Consultant, Makoto Consulting Group, Inc.
Photo of J Steven Perry
J. Steven Perry is a software developer, architect, and general Java nut who has been developing software professionally since 1991. His professional interests range from the inner workings of the JVM to UML modeling and everything in between. Steve has a passion for writing and mentoring; he is the author of Java Management Extensions (O'Reilly), Log4j (O'Reilly), and the IBM developerWorks articles "Joda-Time" and OpenID for Java Web applications." In his spare time, he hangs out with his three kids, rides his bike, and teaches yoga.

Summary:  In Part 1 of this tutorial, professional Java™ programmer J. Steven Perry introduced the Java language syntax and libraries you need to write simple Java applications. Part 2, still geared toward developers new to Java application development, introduces the more-sophisticated programming constructs required for building complex, real-world Java applications. Topics covered include exception handling, inheritance and abstraction, regular expressions, generics, Java I/O, and Java serialization.

View more content in this series

Date:  19 Aug 2010
Level:  Introductory PDF:  A4 and Letter (904 KB | 53 pages)Get Adobe® Reader®

Comments:  

Generics

The introduction of generics in JDK 5 marked a huge leap forward for the Java language. If you've used C++ templates, you'll find that generics in the Java language are similar, but not exactly the same. If you haven't used C++ templates, then don't worry: This section offers a high-level introduction to generics in the Java language.

What are generics?

With the release of JDK 5, the Java language suddenly sprouted strange and exciting new syntax. Basically, some familiar JDK classes were replaced with their generic equivalents.

Generics is a compiler mechanism whereby you can create (and use) types of things (such as classes or interfaces) in a generic fashion by harvesting the common code and parameterizing (or templatizing) the rest.

Generics in action

To see what a difference generics make, consider the example of a class that has been in the JDK for a long time: java.util.ArrayList, which is a List of Objects that is backed by an array.

Listing 21 shows how java.util.ArrayList is instantiated:


Listing 21. Instantiating ArrayList

ArrayList arrayList = new ArrayList();
arrayList.add("A String");
arrayList.add(new Integer(10));
arrayList.add("Another String");
// So far, so good.

As you can see, the ArrayList is heterogeneous: it contains two String types and one Integer type. Before JDK 5 there was nothing in the Java language to constrain this behavior, which caused many coding mistakes. In Listing 21, for example, everything is looking good so far. But what about accessing the elements of the ArrayList, which Listing 22 tries to do?


Listing 22. An attempt to access elements in ArrayList

ArrayList arrayList = new ArrayList();
arrayList.add("A String");
arrayList.add(new Integer(10));
arrayList.add("Another String");
// So far, so good.
*processArrayList(arrayList);
*// In some later part of the code...
private void processArrayList(ArrayList theList) {
   for (int aa = 0; aa < theList.size(); aa++) {
     // At some point, this will fail...
     String s = (String)theList.get(aa);
   }
}

Without prior knowledge of what's in the ArrayList, you either must check the element you want to access to see if you can handle its type, or face a possible ClassCastException.

With generics, you can specify the type of item that went in the ArrayList. Listing 23 shows how:


Listing 23. A second attempt, using generics

ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("A String");
arrayList.add(new Integer(10));// compiler error!
arrayList.add("Another String");
// So far, so good.
*processArrayList(arrayList);
*// In some later part of the code...
private void processArrayList(ArrayList<String> theList) {
   for (int aa = 0; aa < theList.size(); aa++) {
     // No cast necessary...
     String s = theList.get(aa);
   }
}

Iterating with generics

Generics enhance the Java language with special syntax for dealing with entities like Lists that you commonly want to step through, element by element. If you want to iterate through ArrayList, for instance, you could rewrite the code from Listing 23 like so:

private void processArrayList(ArrayList<String> theList) {
 for (String s : theList) {
   String s = theList.get(aa);
 }
}

This syntax works for any type of object that is Iterable (that is, implements the Iterable interface).


Parameterized classes

Parameterized classes really shine when it comes to collections, so that's how you'll look at them. Consider the (real) List interface. It represents an ordered collection of objects. In the most common use case, you add items to the List and then access those items either by index or by iterating over the List.

If you're thinking about parameterizing a class, consider whether the following criteria apply:

  • A core class is at the center of some kind of wrapper: that is, the "thing" at the center of the class might apply widely, and the features (attributes, for example) surrounding it are identical.
  • Common behavior: you do pretty much the same operations regardless of the "thing" at the center of the class.

Applying these two criteria, it's pretty obvious that a collection fits the bill:

  • The "thing" is the class of which the collection comprises.
  • The operations (such as add, remove, size, and clear) are pretty much the same regardless of the object of which the collection is comprised.

A parameterized List

In generics syntax, the code to create a List looks like this:

List<E> listReference = new concreteListClass<E>();

The E, which stands for Element, is the "thing" I mentioned earlier. The concreteListClass is the class from the JDK you are instantiating. The JDK includes several List<E> implementations, but you'll use ArrayList<E>. Another way you might see a generic class discussed is Class<T>, where T stands for Type. When you see E in Java code, it's usually referring to a collection of some kind. And when you see T, it's denoting a parameterized class.

So, to create an ArrayList of, say, java.lang.Integer, you'd do this:

List<Integer> listOfIntegers = new ArrayList<Integer>();

SimpleList: A parameterized class

Now suppose you want to create your own parameterized class called SimpleList, with three methods:

  • add() adds an element to the end of the SimpleList.
  • size() returns the current number of elements in the SimpleList.
  • clear() completely clears the contents of the SimpleList.

Listing 24 shows the syntax to parameterize SimpleList:


Listing 24. Parameterizing SimpleList

package com.makotogroup.intro;
import java.util.ArrayList;
import java.util.List;
public class SimpleList<E> {
 private List<E> backingStore;
 public SimpleList() {
   backingStore = new ArrayList<E>();
 }
 public E add(E e) {
   if (backingStore.add(e))
     return e;
   else
     return null;
 }
 public int size() {
   return backingStore.size();
 }
 public void clear() {
   backingStore.clear();
 }
}

SimpleList can be parameterized with any Object subclass. To create and use a SimpleList of, say, java.math.BigDecimal objects, you'd do this:

public static void main(String[] args) {
 SimpleList<BigDecimal> sl = new SimpleList<BigDecimal>();
 sl.add(BigDecimal.ONE);
 log.info("SimpleList size is : " + sl.size());
 sl.add(BigDecimal.ZERO);
 log.info("SimpleList size is : " + sl.size());
 sl.clear();
 log.info("SimpleList size is : " + sl.size());
}

And you'd get this output:

May 5, 2010 6:28:58 PM com.makotogroup.intro.Application main
INFO: SimpleList size is : 1
May 5, 2010 6:28:58 PM com.makotogroup.intro.Application main
INFO: SimpleList size is : 2
May 5, 2010 6:28:58 PM com.makotogroup.intro.Application main
INFO: SimpleList size is : 0


Enum types

In JDK 5, a new data type was added to the Java language, called enum. Not to be confused with java.util.Enumeration, enum represents a set of constant objects that are all related to a particular concept, each of which represents a different constant value in that set. Before enum was introduced to the Java language, you would have defined a set of constant values for a concept (say, gender) like so:

public class Person {
 public static final String MALE = "male";
 public static final String FEMALE = "female";
}

Whatever code needed to reference that constant value would have been written something like this:

public void myMethod() {
 //. . .
 String genderMale = Person.MALE;
 //. . .
}

Defining constants with enum

Using the enum type makes defining constants much more formal, and also more powerful. Here's the enum definition for Gender:

public enum Gender {
 MALE,
 FEMALE
}

That just scratches the surface of what you can do with enums. In fact, enums are much like classes, so they can have constructors, attributes, and methods:

package com.makotogroup.intro;

public enum Gender {
 MALE("male"),
 FEMALE("female");

 private String displayName;
 private Gender(String displayName) {
   this.displayName = displayName; 
 }

 public String getDisplayName() {
   return this.displayName;
 }
}

One difference between a class and an enum is that an enum's constructor must be declared private, and it cannot extend (or inherit from) other enums. However, an enum can implement an interface.

An enum implements an interface

Suppose you define an interface, Displayable:

package com.makotogroup.intro;
public interface Displayable {
 public String getDisplayName();
}

Your Gender enum could implement this interface (as well as any other enum that needed to produce a friendly display name), like so:

package com.makotogroup.intro;

public enum Gender implements Displayable {
 MALE("male"),
 FEMALE("female");

 private String displayName;
 private Gender(String displayName) {
   this.displayName = displayName; 
 }
 @Override
 public String getDisplayName() {
   return this.displayName;
 }
}

See Resources to learn more about generics.

9 of 14 | Previous | Next

Comments



static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=508383
TutorialTitle=Introduction to Java programming, Part 2: Constructs for real-world applications
publish-date=08192010
author1-email=steve@makotoconsulting.com
author1-email-cc=jaloi@us.ibm.com