Home arrow Java arrow Page 7 - Java in Review
JAVA

Java in Review


Tired of hearing about the gory syntax details of Java? Keep reading for a more conceptual view of the language, focusing on important issues that deserve more attention than they usually receive. Even an advanced programmer will find useful information in this article. It was excerpted from chapter one of Hardcore Java, edited by Robert Simmons Jr. (O'Reilly, 2004; ISBN: 0596005687).

Author Info:
By: O'Reilly Media
Rating: 4 stars4 stars4 stars4 stars4 stars / 12
June 16, 2005
TABLE OF CONTENTS:
  1. · Java in Review
  2. · Syntax Issues
  3. · Collection iteration with for
  4. · Labels
  5. · Assertions versus exceptions
  6. · Assertions and deployment
  7. · Initialization
  8. · Access Issues
  9. · Common Mistakes

print this article
SEARCH DEVARTICLES

Java in Review - Initialization
(Page 7 of 9 )

Initialization is the process of assigning values to variables prior to the execution of the constructor for a class. Initialization is used in many places, and is often poorly understood by developers. Many developers think of initialization as one topic, when, in fact, there are six types of initialization that you can use in your code. The simplest type of initialization is shown here:

  package oreilly.hcj.review;
  public class InitalizerDemo {
   
public String description = "An initialized member";
 
}

The variable description in this class is assigned the value of "An initialized member" just prior to construction of each instance of the object. Therefore, even if the constructor does not explicitly set description, it will be guaranteed to contain the value set in the initializer.

This type of initialization is important for solidifying code because it allows you to preset instance attributes to default values before the constructor is called. In this manner, constructors can ignore these attributes if they wish. Although this type of initialization is useful, there are times when initializations need to be a bit more complex:

  package oreilly.hcj.review;
  public class InitalizerDemo {
   
public long timestamp = System.currentTimeMillis();
 
}

In this initializer, you can call a method on the line of the initialization. This ability allows you to perform more complex initializations that would be impossible without a method. However, keep in mind that methods used in initializers are under the same restrictions as the helper methods for chained constructors that we discussed earlieróthey should be static and canít use the this pointer.

In fact, you donít even need to define a helper method if you donít want to; an initializer can be a method itself:

  package oreilly.hcj.review;
  public class InitalizerDemo {
   
private String xmlClasspath;
    {
     
final StringBuffer buf = new StringBuffer(500);
     
final String classPath = System.getProperty("java.class.path");
     
StringTokenizer tok = new StringTokenizer(classPath,
                    System.getProperty("path.separator"));
    buf.append("<classpath>\n");
    while (tok.hasMoreTokens()) {
       
buf.append(" <pathelement location=\"");
       
buf.append(tok.nextToken());
       
buf.append("\"/>\n");
    
}
     
buf.append("</classpath>");
      xmlClasspath = buf.toString();
    }
 
}

In this code, you translate the classpath into an XML structure upon initialization of the object. This code will work fine, as you can see by running the oreilly.hcj. review.InitializerDemo class in the example code:

  >ant -Dexample=oreilly.hcj.review.InitializerDemo run_example
  run_example:
      [java] ------Dumping Contents-----------
      [java] ---------------------------------
      [java] Initializer Demo
      [java] x86
      [java] C:\Documents and Settings\Robert
      [java] An initialized member
      [java] <classpath>
      [java] <pathelement location="c:\j2sdk\\lib\tools.jar"/>
      [java] <pathelement location="C:\j2sdk\addons\jakarta-ant-1.5\bin\\..\lib\xmlapis.
jar"/>
      [java] <pathelement location="C:\j2sdk\addons\jakarta-ant-1.5\bin\\..\lib\
xercesImpl.jar"/>
      [java] <pathelement location="C:\j2sdk\addons\jakarta-ant-1.5\bin\\..\lib\
optional.jar"/>
      [java] <pathelement location="C:\j2sdk\addons\jakarta-ant-1.5\bin\\..\lib\ant.
jar"/>
      [java] </classpath>
      [java] ---------------------------------

Although this initialization technique is useful, you shouldnít use it routinely. Instead, it should be saved for special circumstances, as it makes code a little cryptic to read. Use it only when you really need a special multiline initialization.

Instance attributes arenít the only kind of attributes in a class. Attributes declared with the static keyword are class-scoped. Class-scoped attributes can be initialized in a manner similar to instance-scoped attributes. Here is a simple case:

  package oreilly.hcj.review;
  public class InitalizerDemo {
   
public static final String NAME = "Initializer Demo";
 
}

This code works exactly like the instance initializer, except that it is called when the class is loaded into the virtual machine by the ClassLoader. Another difference is that this attribute is final, so it cannot be changed after it is initialized.


Although I show final class-scoped attributes in the examples, keep in mind that the behavior of class-scoped attributes that are not final is identical to that of final class-scoped attributes.

Like instance initializers, you can call methods in static variable initialization:

  package oreilly.hcj.review;
  public class InitalizerDemo {
    public static final String ARCH =
System.getProperty("os.arch");
  }

You can also defer an initialization of a static variable to do something more complex:

  package oreilly.hcj.review;
  public class InitalizerDemo {
   
public static final String USER_HOME;
 
}

In this code, you have created a constant without giving the constant a value. Perhaps the value you want requires more complex code than a simple assignment. This is where the special static{} method comes in. The ClassLoader automatically invokes all static{} initializer methods when the class is loaded into the virtual machine. It is in this method only that you can initialize final static variables that are not initialized on their declaration line. You can use this method in a similar manner as the method-based instance initializers:

  package oreilly.hcj.review;
  public class InitalizerDemo {
    public static final String USER_HOME;
   
static{
      USER_HOME = System.getProperty("user.home");
    }
 
}

The variable USER_HOME will be filled with the string version of the userís home directory from the system properties. The value will then be final for the duration of the life of the virtual machine.

While using the static{} method, it is important to keep order in mind. Since static initializers are called in order of their declaration, you can get into a bit of trouble if you arenít careful:

  public static class Values{
    public final static String VALUE_ONE = "Blue";
   
static {
      System.out.println("static{} method for One");  
      System.out.println(VALUE_ONE);
     
System.out.println(VALUE_TWO); // <= compiler error
   
}
    
public final static String VALUE_TWO = "Red";
  }

In this code, the compiler cannot find VALUE_TWO because it has not been declared at the time when the static{} method was run. Since initializers are processed in order, you get a bug called an illegal forward reference. Get rid of the bug with a coding standard that declares all static variables first, and then declares static methods. This will keep you out of trouble with your compiler (although not necessarily with your programming logic).

While order is important, be aware that you cannot depend on the order of static initialization. Any methods that depend on ordering are likely to end up with some strange results. To make things a bit clearer, letís intentionally build an example of this problem. Example 1-8 shows the constructed bug.

Example 1-8. Erroneous dependence on static initializer order

  package oreilly.hcj.review;
  public class StaticOrderDemo {
   
public StaticOrderDemo(){
    }
   
public static final void main(final String[] args) {
    }
 
public static class Ranges {
    public static final String[] RANGE_BLUE = { "Sky", "Navy" };
   
public static final String[] RANGE_RED = { "Light", "Dark" };
   
static {
      System.out.println("static{} method for Ranges"); 
      System.out.println(Arrays.asList(RANGE_BLUE)); 
      System.out.println(Values.VALUE_SPECIFIER); 
      System.out.println(Arrays.asList(RANGE_RED));
   
}
  }
 
public static class Values {
    public static final String VALUE = "Blue";
   
public static final String VALUE_SPECIFIER;
   
static {
      System.out.println("static{} method for Values");
      System.out.println(VALUE);
      System.out.println(Ranges.RANGE_BLUE);
      VALUE_SPECIFIER = Ranges.RANGE_BLUE[1];
   
}
   }
  }

When the example is run, the static nested class Ranges is initialized first. As a result, you will see the following output:

  >ant -Dexample=oreilly.hcj.review.StaticOrderDemo run_example
  run_example:
 
[java] static{} method for Values
  [java] Blue
  [java] static{} method for Ranges
  [java] [Sky, Navy]
  [java] null
  [java] [Light, Dark]
  [java] [Ljava.lang.String;@1e3118a
  [java] Class oreilly.hcj.review.StaticOrderDemo$Values Loaded

Note especially the null. Since Values.VALUE_SPECIFIER had not been initialized when it was used in the Ranges initializer, its value was null at the time of the System.out.println(). Only microseconds later, when Values finishes initializing, it is no longer null. This kind of bug is very difficult to find because of its very transient life. The moral of this story is that you can never depend on the initialization order of static members.


Although this example was specifically constructed for this book, I actually encountered this bug in production code several times. The first time resulted in an overnight programming frenzy to try to find and correct the bug.

To summarize, there are many kinds of initializers, which are all useful for setting values prior to object construction, but beware of the little gotchas with static initializers. In Example 1-9, all of the possible initializers are shown in one class.

Example 1-9. All the various initializers together

  package oreilly.hcj.review;
 
public class InitalizerDemo {
   
/** Simple static initialization. */
   
public static final String NAME = "Initializer Demo";
   
/** Initialized static on one line. */
    public static final String ARCH = System.getProperty("os.arch");
   
/** Static method based initialization. */
    public static final String USER_HOME;
   
static {
      USER_HOME = System.getProperty("user.home");
    }
   
/** Simple instance member initialization. */
    public String description = "An initialized member";
   
/** Method call instance member initialization. */ 
    public long timestamp = System.currentTimeMillis();
   
/** Complex instance member initialization. */
    private String xmlClasspath;
    {
      
final StringBuffer buf = new StringBuffer(500);
      final
String classPath = System.getProperty("java.class.path");
      StringTokenizer tok =
       
new StringTokenizer(classPath,
                    
System.getProperty("path.separator"));
      buf.append("<classpath>\n");
      while (tok.hasMoreTokens()) {
        
buf.append(" <pathelement location=\"");
       
buf.append(tok.nextToken());
        
buf.append("\"/>\n");
      
}
      buf.append("</classpath>\n");
      
xmlClasspath = buf.toString();
    
}
  }

One final thing to remember about all initializers is that you cannot throw any exceptions other than subclasses of RuntimeException within the initializer. All other exceptions will cause all sorts of compilation errors. Therefore, if you want to use methods that throw other types of exceptions, you will have to wrap up any possible exceptions in a try and catch block and then throw a RuntimeException; of course, youíre caught up on chained exceptions by now, so this is no problem. With this arsenal of initializers at your command, you should be ready to tackle setting defaults for any type of class you can think of.


blog comments powered by Disqus
JAVA ARTICLES

- Java Too Insecure, Says Microsoft Researcher
- Google Beats Oracle in Java Ruling
- Deploying Multiple Java Applets as One
- Deploying Java Applets
- Understanding Deployment Frameworks
- Database Programming in Java Using JDBC
- Extension Interfaces and SAX
- Entities, Handlers and SAX
- Advanced SAX
- Conversions and Java Print Streams
- Formatters and Java Print Streams
- Java Print Streams
- Wildcards, Arrays, and Generics in Java
- Wildcards and Generic Methods in Java
- Finishing the Project: Java Web Development ...

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials