Java
  Home arrow Java arrow Page 7 - Java in Review
Dev Articles Forums 
ADO.NET  
Apache  
ASP  
ASP.NET  
C#  
C++  
ColdFusion  
COM/COM+  
Delphi-Kylix  
Design Usability  
Development Cycles  
DHTML  
Embedded Tools  
Flash  
Graphic Design  
HTML  
IIS  
Interviews  
Java  
JavaScript  
MySQL  
Oracle  
Photoshop  
PHP  
Reviews  
Ruby-on-Rails  
SQL  
SQL Server  
Style Sheets  
VB.Net  
Visual Basic  
Web Authoring  
Web Services  
Web Standards  
XML  
Mobile Linux 
App Generation ROI 
IBM® developerWorks 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
JAVA

Java in Review
By: O'Reilly Media
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 6
    2005-06-16

    Table of Contents:
  • Java in Review
  • Syntax Issues
  • Collection iteration with for
  • Labels
  • Assertions versus exceptions
  • Assertions and deployment
  • Initialization
  • Access Issues
  • Common Mistakes

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT


    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.

    More Java Articles
    More By O'Reilly Media


     

    Buy this book now. This article was excerpted from chapter one of Hardcore Java, edited by Robert Simmons Jr. (O'Reilly, 2004; ISBN: 0596005687). Check it out at your favorite bookstore. Buy this book now.

    JAVA ARTICLES

    - 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 ...
    - Generics and Limitations in Java
    - Getting Started with Java Web Development in...







    © 2003-2010 by Developer Shed. All rights reserved. DS Cluster 9 Hosted by Hostway
    For more Enterprise Application Development news, visit eWeek