Java
  Home arrow Java arrow Page 4 - 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  
Dedicated Servers  
Moblin 
JMSL Numerical Library 
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 - Final Collections


    (Page 4 of 7 )

    Periodically, while programming, you may want to make constant sets and store them in final variables for public use. This desire can lead to all sorts of problems. Consider the code in Example 2-11.

    Example 2-11. A collection in a final static member

    package oreilly.hcj.finalstory;
    public class FinalCollections {
     
    public static class Rainbow {
       
    public final static Set VALID_COLORS;
       
    static {
           VALID_COLORS = new HashSet(); 
          VALID_COLORS.add(Color.red);
          VALID_COLORS.add(Color.orange);
          VALID_COLORS.add(Color.yellow);
          VALID_COLORS.add(Color.green);
          VALID_COLORS.add(Color.blue);
          VALID_COLORS.add(Color.decode("#4B0082")); // indigo
          VALID_COLORS.add(Color.decode("#8A2BE2")); // violet
        
    }
      }
    }

    The goal of this code is to declare a class with aSetoffinalandstatic Colors representing the colors of the rainbow. You want to be able to use thisSetwithout concerning yourself with the possibility of accidentally changing it. The problem is that theSetisn’tfinalat all! Break it with Example 2-12.

    Example 2-12. A defect caused by a nonimmutable set

    package oreilly.hcj.finalstory;
    public final static void someMethod() {
      Set colors = Rainbow.VALID_COLORS;
     
    colors.add(Color.black); // <= logic error but allowed by compiler
      System.out.println(colors);
    }

    The reference to theSet is final, but theSet itself is mutable. In short, your constant variable isn’t very constant. The point is thatfinalis not the same as immutable.

    You can firm up this code in the same way you locked down returned collections from a bean in Chapter 1:

    package oreilly.hcj.finalstory;
    public static class RainbowBetter {
        
    public final static Set VALID_COLORS;
       
    static {
           Set temp = new HashSet();
          temp.add(Color.red);
          temp.add(Color.orange);
          temp.add(Color.yellow);
          temp.add(Color.green);
          temp.add(Color.blue);
          temp.add(Color.decode("#4B0082")); // indigo
          temp.add(Color.decode("#8A2BE2")); // violet
          VALID_COLORS = Collections.unmodifiableSet(temp);

        }
      }
    }

    This version of the class is much better. YourSet ofColors cannot be modified because you have turned it into an immutable object. The reference to theSetisfinal, and the contents of the collection are locked down.

    In thestatic{}initializer, note how you have to use a temporary set to store the colors. This is because you can set afinalvariable only once, even in the initializer. If you try to set it more than once or change the variable in the initializer, your compiler will give an error message stating that you cannot change thefinalvariable. Remember that deferredfinals are a one-shot deal. Once set (no pun intended), they can’t be changed.

    Now that you have a strategy to lock down your Set, let’s revisit the old logic bug that we discussed in Example 2-12:

    package oreilly.hcj.finalstory;
    public final static void someMethod() {
      Set colors = RainbowBetter.VALID_COLORS;
     
    colors.add(Color.black); // <= exception here
     
    System.out.println(colors);
    }

    Now that you have theSetlocked down, this code results in an exception. Specifically, the method will throw anUnsupportedOperationExceptionwhenever the user tries to use any write methods onVALID_COLORS, as it is now immutable. In this case, you haven’t been able to trade a logic bug for a compiler bug, but you have been able to trade a logic bug for an exception. Although this trade isn’t as good, it’s still definitely worthwhile. Always use thejava.util.Collectionsclass to get unmodifiable collections and maps when creatingfinalcollections and maps.

    As far as unmodifiable sets go, the performance hit is negligible. As it turns out, the JDK implements unmodifiable collections in a performance-conscious way. If you look into the JDK source, you will see the static nested classesUnmodifiableSet andUnmodifableCollection. The code in Example 2-13* is pasted directly from the JDK source. All I did was change the spacing to conform to O’Reilly standards and remove the Javadoc for brevity’s sake.

    Example 2-13. Implementation of unmodifiable collections

    package oreilly.hcj.finalstory;
    public static Collection unmodifiableCollection(Collection c) {
      return new UnmodifiableCollection(c);
    }
    static class UnmodifiableCollection implements Collection, Serializable {
      // use serialVersionUID from JDK 1.2.2 for interoperability
      private static final long serialVersionUID = 1820017752578914078L;
     
    Collection c;
     
    UnmodifiableCollection(Collection c) {
        if (c==null)
           throw new NullPointerException(); 
        this.c = c;
      }
     
    public int size()      {return c.size();}
      public boolean isEmpty() {return c.isEmpty();}
      public boolean contains(Object o)  {return c.contains(o);}
      public Object[] toArray()   {return c.toArray();}
      public Object[] toArray(Object[] a) {return c.toArray(a);}
      public String toString()  {return c.toString();}
     
    public Iterator iterator() {
        return new Iterator() {
          Iterator i = c.iterator();
       
    public boolean hasNext() {return i.hasNext();}
          public Object next() {return i.next();}
            public void remove() {
              throw new UnsupportedOperationException();
          }
        };
      }
      public boolean add(Object o){
        throw new UnsupportedOperationException();
      }
     
    public boolean remove(Object o) {
        throw new UnsupportedOperationException();
      }
     
    public boolean containsAll(Collection coll) {
        return c.containsAll(coll);
      }
     
    public boolean addAll(Collection coll) {
        throw new UnsupportedOperationException();
      }
     
    public boolean removeAll(Collection coll) {
        throw new UnsupportedOperationException();
      }
     
    public boolean retainAll(Collection coll) {
        throw new UnsupportedOperationException();
      }
     
    public void clear() {
        throw new UnsupportedOperationException();
      }
    }
    public static Set unmodifiableSet(Set s) {
      return new UnmodifiableSet(s);
    }

    * From JDK source Java.util.Collections.

    When you callCollections.unmodifiableSet(), the class creates a new instance of this static nested class and sets the source collection as the delegate object. As you can see in the example code from the JDK, the classUnmodifiableSetimplementsjava.util.Setand inherits fromUnmodifiableCollection, which in turn implementsjava.util.Collection. Together, they form a delegate structure. Any read call to theUnmodifiableCollectionis forwarded to the delegate collection. However, if the user tries to access a write operation, the class throws an instance ofUnsupportedOperationException. Therefore, the additional overhead of theUnmodifiableSet is only a single method call.

    This delegate structure also plugs another big hole: if theUnmodifiableSetclass inherited fromHashSet, then the user could just cast the instances back toHashSetto gain access to write methods. The delegate structure in the JDK quite elegantly blocks this, ensuring that anUnmodifiableSettruly is unmodifiable, even when placed in the hands of a clever and sneaky programmer.

    All of the other collection classes work similarly toUnmodifiableSet. You should use these heavily in your code. Regrettably, there is no similar way to lock downfinalarray objects, so be careful when using them.

    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 6 hosted by Hostway