Java
  Home arrow Java arrow Page 2 - The Final (Constants) Story
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 
Sun Developer Network 
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

The Final (Constants) Story
By: O'Reilly Media
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 5 stars5 stars5 stars5 stars5 stars / 4
    2005-10-20

    Table of Contents:
  • The Final (Constants) Story
  • Excessive Constants
  • Deferred Initialization
  • Final Collections
  • Instance-Scoped Variables
  • Final Methods
  • Conditional Compilation Variable Location

  • 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


    The Final (Constants) Story - Excessive Constants


    (Page 2 of 7 )

    The overuse of class-scoped constants is another common trap that can clutter up otherwise well-built code. For example, consider a situation in which there are many constants in a mathematically oriented class, as shown in Example 2-4.

    Example 2-4. Excessive use of private constants

    package oreilly.hcj.finalstory;
    public class FinalConstants {
      public class SomeClass {
        /** Contains the constant for the first equation. */
        private static final double K1 = 3.141;
        
    /** Contains the offset for the first equation. */
        private static final double X1 = 15.0;
       
    /** Contains the constant for the second equation. */
        private static final double K2 = 1.414;
       
    /** Contains the offset for the second equation. */
        private static final double X2 = 45.0;
        
    /** Contains a constant for both equations. */
        private static final double M = 9.3;
        
    public double equation1(final double inputValue) {
          return (((Math.pow(inputValue, 2.0d) / K1) + X1) / M);
        }
        
    public double equation2(final double inputValue) {
          return (((Math.pow(inputValue, 3.0d) * K2) + X2) * M);
        }
      }
    }

    Although there is nothing technically wrong with this code, it is a rather nasty mess. If your equations become large, with multiple constants and numerous terms, the situation turns into something more appropriate for a horror movie. To avoid this trap, rewrite this disaster:

    package oreilly.hcj.finalstory;
    public class FinalConstants {
     
    public class SomeClassBetter {
        /** Contains a constant for both equations. */
        private static final double M = 9.3;
       
    public double equation1(final double inputValue) {
         
    final double K = 3.141;
          final double X = 15.0;
          
    return (((Math.pow(inputValue, 2.0d) / K) + X) / M);
        }
        public double equation2(final double inputValue) {
         
    final double K = 1.414;
         final double X = 45.0; 
         re
    turn (((Math.pow(inputValue, 3.0d) * K) + X) * M);
        }
      }
    }

    Although the method-scopedfinalvariables may look strange, they are quite legal and useful. For the compiler, the semantics for method-scoped constants are the same as those for class-scoped constants. The compiler will replace primitive andStringconstant variables with the value of the variable at compile time.

    In fact, since the constants in Example 2-4 are private, you know that they cannot be accessed outside of the class, so there is no reason to leave them in the scope of the class. In the process of making your code easier to read and understand, you removed the need for those silly1s and2s in your constant names. Since the constants are used only in those methods, it is appropriate to restrict them to the methods in which they are used.


    Take Advantage of Warning Options in Good Development Tools

    Good tools can really help you to identify private variables and mistakes associates with them. For example, my IDE is configured to warn me if a private member of a class is not used in that class. Not only does this help me find private constants that should have been declared public, it also helps me clean up code that has been developed for a while and may have accumulated some lint throughout the process. Eclipse, for example, has many of these options; you should turn on all of them to warning level. Using these warnings can save you a lot of debugging time down the road.


     

    To summarize, if you have aprivate final staticthat is used only in one method, you should probably move it into that method. On the other hand, if the constants are being used in more than one method, you should leave them as class-scoped. The constantMwas not moved because it was being used by two of the methods.

    Final Variables

    While we are on the subject of scoped final variables, you should keep in mind that these variables don’t have to be primitives to be useful. Final variables that are scoped and constructed can be used as a powerful tool to solidify code in methods.

    Method-Scoped final Variables

    Although final variables that appear within methods are a little strange to some people at first, they become quite addictive once you get used to reading them. See Example 2-5.

    Example 2-5. Catching mistakes with method-scoped final variables

    package oreilly.hcj.finalstory;
    public class FinalVariables {
      public static String someMethod(final String environmentKey) {
        
    final String key = "env." + environmentKey;
        
    System.out.println("Key is: " + key);
        return (System.getProperty(key));
      }
    }

    In this class, you build a scopedfinalvariable that adds a prefix to the parameterenvironmentKey. In this case, thefinalvariable is final only within the execution scope, which is different at each execution of the method. Each time the method is entered, thefinalis reconstructed. As soon as it is constructed, it cannot be changed during the scope of the method execution. This allows you to fix a variable in a method for the duration of the method. To see how this works, use the test program in Example 2-6.

    Example 2-6. Testing final variables

    package oreilly.hcj.finalstory;
    public class FinalVariables {
     
    public final static void main(final String[] args){
        System.out.println("Note how the key variable is changed.");
        someMethod("JAVA_HOME");
        someMethod("ANT_HOME");
      }
    }

    Running this test program results in the following:

    >ant -Dexample=oreilly.hcj.finalstory.FinalVariables run_example
    run_example:
         [java] Note how the key variable is changed.
         [java] Key is:
    env.JAVA_HOME
         [java] Key is:
    env.ANT_HOME

    Each time the method is entered, the passed-in environmentKey parameter is appended to the constant prefix and then frozen for the duration of the method call. So why make the variable final? Because once this variable is set in the body of the method, it cannot be changed. Consider what would happen if you made a mistake like the one shown in Example 2-7.

    Example 2-7. A coding mistake caught by a final variable

    package oreilly.hcj.finalstory;
    public class FinalVariables {
     
    public static String someBuggedMethod(final String environmentKey){
        final String key = "env." + environmentKey;
        System.out.println("Key is: " + key);
       
    key = new String("someValue"); // <= compiler error. 
       
    return (System.getProperty(key));
      }
    }

    When you try to compile this code, it will give the following result:

    >ant -Dexample=oreilly/hcj/finalstory/FinalVariables.java compile_example
    compile_example:
        [javac] Compiling 1 source file to C:devhcjbin 
        [javac]
    C:devhcjsrcoreillyhcjfinalstoryFinalVariables.java:53:cannot
    assign a value to final variable key
        [javac]   key = new String("someValue"); // <= compiler error.
        [javac]   ^
        [javac] 1 error


    In the example code, I commented out the compiler error; you will have to uncomment it to run this test. I use a similar procedure for all compiler errors throughout the book.


    In this example, the mistake was made of trying to reassignkeyto a different value. This type of mistake simply happens; however, since you are a savvy programmer, and you used thefinalkeyword, the compiler tells you that an error was made. This is a great example of trading a logic error for a compiler error.

    The technique of fixing variables withfinalis extremely handy for long or complicated methods that have many local variables. When alerted by the compiler, repairing this mistake takes a matter of seconds. If you don’t use finalto fix your variables now, you run the risk of spending long hours to find logic bugs, only to discover that someone reset your variable halfway through the method because of a typo.

    More Java Articles
    More By O'Reilly Media


       · This article is an excerpt from the book "Hardcore Java", published by O'Reilly. We...
     

    Buy this book now. This article is excerpted from chapter two of Hardcore Java, written 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-2008 by Developer Shed. All rights reserved. DS Cluster 4 hosted by Hostway
    Stay green...Green IT