★ wanayoo — archive 1999 http://developer.java.sun.com/developer/Books/corejava/page7.htmlNouvelle recherche | Portail wanayoo
Java Technology Home Page
A-Z Index

Java Developer Connection(SM)
Books

Downloads, APIs, Documentation
Java Developer Connection
Tutorials, Tech Articles, Training
Online Support
Community Discussion
News & Events from Everywhere
Products from Everywhere
How Java Technology is Used Worldwide
 
Book Excerpt Index

Core Java 2, Volume II

by Cay S. Horstmann and Gary Cornell

Chapter 2: Collections



Property Defaults

A property set is also a useful gadget whenever you want to allow the user to customize an application. Here is how your users can customize the NotHelloWorld program to their hearts' content. We'll allow them to specify the following in the configuration file CustomWorld.ini:

  • window size
  • font
  • point size
  • background color
  • message string
If the user doesn't specify some of the settings, we will provide defaults.

The Properties class has two mechanisms for providing defaults. First, whenever you look up the value of a string, you can specify a default that should be used automatically when the key is not present.

String font = 
  settings.getProperty("FONT", "Courier");
If there is a "FONT" property in the property table, then font is set to that string. Otherwise, font is set to "Courier".

If you find it too tedious to specify the default in every call to getProperty, then you can pack all the defaults into a secondary property set and supply that in the constructor of your lookup table.

Properties defaultSettings = 
                     new Properties();
defaultSettings.put("FONT", "Courier");
defaultSettings.put("SIZE", "10");
defaultSettings.put(
           "MESSAGE", "Hello, World");
. . .
Properties settings = 
      new Properties(defaultSettings);
FileInputStream sf = 
  new FileInputStream("CustomWorld.ini");
settings.load(sf);
. . .
Yes, you can even specify defaults to defaults if you give another property set parameter to the defaultSettings constructor, but it is not something one would normally do.

Figure 2-12 is the customizable "Hello World" program. Just edit the .ini file to change the program's appearance to the way you want (see Figure 2-12).


Figure 2-12: The customized Hello World program

Here are the current property settings.

FONT=Times New Roman
SIZE=400 200
MESSAGE=Hello, Custom World
COLOR=0 50 100
PTSIZE=36

NOTE: The Properties class extends the Hashtable class. That means, all methods of Hashtable are available to Properties objects. Some functions are useful. For example, size returns the number of possible properties (well, it isn't that nice--it doesn't count the defaults). Similarly, keys returns an enumeration of all keys, except for the defaults. There is also a second function, called propertyNames , that returns all keys. The put function is downright dangerous. It doesn't check that you put strings into the table.

Does the is-a rule for using inheritance apply here? Is every property set a hash table? Not really. That these are true is really just an implementation detail. Maybe it is better to think of a property set as having a hash table. But then the hash table should be a private data field. Actually, in this case, a property set uses two hash tables, one for the defaults and one for the nondefault values.

We think a better design would be the following:

 class Properties
 {  public String getProperty(String) 
                              { . . . }
    public void put(String, String) 
                              { . . . }
    . . .
    private Hashtable nonDefaults;
    private Hashtable defaults;
 }
   
We don't want to tell you to avoid the Properties class in the Java library. Provided you are careful to put nothing but strings in it, it works just fine. But think twice before using quick and dirty inheritance in your own programs.

Example 2-6: CustomWorld.java


import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import javax.swing.*;

public class CustomWorld
{  public static void main(
              String[] args)
   {  JFrame frame = 
      new CustomWorldFrame();
      frame.show();  
   }
}

class CustomWorldFrame extends JFrame
{  public CustomWorldFrame()
  {  addWindowListener(new WindowAdapter()
         {  public void windowClosing(
                            WindowEvent e)
            {  System.exit(0);
            }
         } );

      Properties defaultSettings = 
                        new Properties();
      defaultSettings.put(
                   "FONT", "Monospaced");
      defaultSettings.put(
                      "SIZE", "300 200");
      defaultSettings.put(
              "MESSAGE", "Hello, World");
      defaultSettings.put(
                     "COLOR", "0 50 50");
      defaultSettings.put(
                        "PTSIZE", "12");
   
      Properties settings = 
           new Properties(
                       defaultSettings);
      try
      {  FileInputStream sf 
            = new FileInputStream(
                    "CustomWorld.ini");
         settings.load(sf);
      } 
      catch (FileNotFoundException e) {}
      catch (IOException e) {}
   
      StringTokenizer st = 
                     new StringTokenizer
         (settings.getProperty(
                             "COLOR"));
      int red = Integer.parseInt(
                     st.nextToken());
      int green = 
                Integer.parseInt(
                      st.nextToken());
      int blue = Integer.parseInt(
                     st.nextToken());
      
      Color foreground = 
                  new Color(
                     red, green, blue);
      
      Stringname = 
                 settings.getProperty(
                              "FONT");
      int size = 
        Integer.parseInt(
                  settings.getProperty(
                            "PTSIZE"));
      Font f = new Font(
                 name, Font.BOLD, size);
      
      st = new StringTokenizer(
                settings.getProperty(
                             "SIZE"));
      int hsize = Integer.parseInt(
                       st.nextToken());
      int vsize = Integer.parseInt(
                     st.nextToken());
      setSize(hsize, vsize);
      setTitle(
     settings.getProperty("MESSAGE"));

      getContentPane().add(
       new HelloWorldPanel(getTitle(), 
      foreground, f), "Center");
   }
}

class HelloWorldPanel extends JPanel
{  public HelloWorldPanel(
      String aMessage, 
           Color aForeground, 
      Font aFont)
   {  message = aMessage;
      foreground = aForeground;
      font = aFont;
   }

   public void paintComponent(
                    Graphics g)
   {  super.paintComponent(g);
      g.setColor(foreground);
      g.setFont(font);

      FontMetrics fm = g.getFontMetrics(
                                   font);
      int w = fm.stringWidth(message);

      Dimension d = getSize();
      int cx = (d.width - w) / 2;
      int cy = (d.height + fm.getHeight()) 
                 / 2 - fm.getDescent();
      
      g.drawString(message, cx, cy);
   }

   private Color foreground;
   private Font font;
   privateStringmessage;
}
java.util.Properties
  • Properties()
    creates an empty property list.
  • Properties(Properties defaults)
    creates an empty property list with a set of defaults. Parameters: defaults the defaults to use for lookups
  • StringgetProperty(String key)
    gets a property association; returns the string associated with the key, or the string associated with the key in the default table if it wasn't present in the table.
    Parameters: key the key whose associated string to get
  • String getProperty(String key,StringdefaultValue)
    gets a property with a default value if the key is not found; returns the string associated with the key, or the default string if it wasn't present in the table.
    Parameters: key the key whose associated string to get defaultValue the string to return if the key is not present
  • void load(InputStream in) throws IOException
    loads a property set from an InputStream.
    Parameters: in the input stream
java.util.Stack
  • void push(Object item)
    pushes an item onto the stack. Parameters: item the item to be added
  • Object pop()
    pops and returns the top item of the stack. Don't call this method if the stack is empty.
  • Object peek()
    returns the top of the stack without popping it. Don't call this method if the stack is empty.
Bit Sets

The Java platform BitSet class stores a sequence of bits. (It is not a set in the mathematical sense--bit vector or bit array would have been more appropriate terms.) Use a bit set if you need to store a sequence of bits (for example, flags) efficiently. Because a bit set packs the bits into bytes, it is far more efficient to use a bit set than to use an ArrayList of Boolean objects.

The BitSet class gives you a convenient interface for reading, setting, or resetting individual bits. Use of this interface avoids the masking and other bit-fiddling operations that would be necessary if you stored bits in int or long variables.

For example, for a BitSet named bucketOfBits,

bucketOfBits.get(i)
returns true if the i'th bit is on, and false otherwise. Similarly,
bucketOfBits.set(i)
turns the i'th bit on. Finally,
bucketOfBits.clear(i)
turns the i'th bit off.
C++ NOTE: The C++ bitset template has the same functionality as the Java platform BitSet.

java.util.BitSet

  • BitSet(int nbits)
    constructs a bit set. Parameters: nbits the initial number of bits
  • int length()
    returns the logical length of the bit set: one plus the index of the highest set bit.
  • boolean get(int bit) gets a bit. Parameters: bit the position of the requested bit
  • void set(int bit)
    sets a bit. Parameters: bit the position of the bit to be set
  • void clear(int bit) clears a bit.
    Parameters: bit the position of the bit to be cleared
  • void and(BitSet set)
    logically ANDs this bit set with another. Parameters: set the bit set to be combined with this bit set
  • void or(BitSet set)
    logically ORs this bit set with another. Parameters: set the bit set to be combined with this bit set
  • void xor(BitSet set)
    logically XORs this bit set with another. Parameters: set the bit set to be combined with this bit set
  • void andNot(BitSet set)
    clears all bits in this bitset that are set in the other bit set.. Parameters: set the bit set to be combined with this bit set
The Sieve of Eratosthenes Benchmark

As an example of using bit sets, we want to show you an implementation of the sieve of Eratosthenes algorithm for finding prime numbers. (A prime number is a number like 2, 3, or 5 that is divisible only by itself and 1, and the sieve of Eratosthenes was one of the first methods discovered to enumerate these fundamental building blocks.) This isn't a terribly good algorithm for finding the number of primes, but for some reason it has become a popular benchmark for compiler performance. (It isn't a good benchmark either, since it mainly tests bit operations.)

Oh well, we bow to tradition and include an implementation. This program counts all prime numbers between 2 and 1,000,000. (There are 78,498 primes, so you probably don't want to print them all out.) You will find that the program takes a little while to get going, but eventually it picks up speed.

Without going into too many details of this program, the key is to march through a bit set with one million bits. We first turn on all the bits. After that, we turn off the bits that are multiples of numbers known to be prime. The positions of the bits that remain after this process are, themselves, the prime numbers. Example 2-7 illustrates this program in the Java programming language, and Example 2-8 is the C++ code.



NOTE: Even though the sieve isn't a good benchmark, we couldn't resist timing the two implementations of the algorithm. Here are the timing results on a Pentium-166 with 96 megabytes of RAM, running Windows 98.

Borland C++ 5.4: 3750 milliseconds
JDK 1.2.1: 1640 milliseconds

We have run this test for four editions of Core Java, and this is the first time that the Java programming language beat C++. However, in all fairness, we should point out that the culprit for the bad C++ result is the lousy implementation of the standard bitset template in the Borland compiler. When we reimplemented bitset, the time for C++ went down to 1090 milliseconds. Of course, these are perfect benchmark results because they allow you to put on any spin that you like. If you want to prove that the Java programming language is 50 percent slower than C++, make use of the latter results. Or you can prove that it has now overtaken C++. Point out that it is only fair to compare the language implementation as a whole, including standard class libraries, and quote the first set of numbers.

Example 2-7: Sieve.java

import java.util.*;

public class Sieve
{  public static final boolean PRINT = 
                                 false;

   public static void main(String[] s)
   {  intn= 1000000;
      long start = 
           System.currentTimeMillis();
      BitSet b = new BitSet(n);
      int count = 0;
      int i;
      for (i = 2; i <= n; i++)
         b.set(i);
      i = 2;
      while (i * i <= n)
      {  if (b.get(i))
       {  if (PRINT) System.out.println(i);
            count++;
            int k = 2 * i;
            while (k <= n)
            {  b.clear(k);
               k += i;
            }
         }
         i++;
      }      
      while (i <= n)
      {  if (b.get(i))
       {  if (PRINT) System.out.println(i);
            count++;
         }
         i++;
      }
      long end =  
             System.currentTimeMillis();
      System.out.println(
                    count + " primes");
      System.out.println((
          end - start) + " milliseconds");
   }
}
Example 2-8: Sieve.cpp



template
class bitset
{
public:
   bitset() : bits(
     new char[(N - 1) / 8 + 1]) {}

   bool test(int n)
   {  return (
     bits[n >> 3] & (1 << (
                    n & 7))) != 0;
   }

   void set(int n)
   {  bits[n >> 3] |= 1 << (n & 7);
   }

   void reset(int n)
   {  bits[n >> 3] &= ~(
                 1 << (n & 7));
   }

private:
   char* bits;
};



using namespace std;

int main()
{  const int N = 1000000;
   clock_t cstart = clock();

   bitset b;
   int count = 0;
   int i;
   for (i = 2; i <= N; i++)
      b.set(i);
   i = 2;
   while (i * i <= N)
   {  if (b.test(i))
      {  int k = 2 * i;
         while (k <= N)
         {  b.reset(k);
            k += i;
         }
      }
      i++;
   }      
   for (i = 2; i <= N; i++)
   {  if (b.test(i))
      {
         cout << i << "\n";
         count++;
      }
   }

   clock_t cend = clock();
   double millis = 1000.0
      * (cend - cstart) / 
                   CLOCKS_PER_SEC;

   cout << count << " primes\n"
      << millis << " milliseconds\n";
   
   return 0;
}

BACK | Page 1


About the Authors

CAY S. HORSTMANN is VP of Technology at Preview Software and professor of computer science at San Jose State University. He has written six books on C++, Java technology, and object-oriented development.

GARY CORNELL has a Ph.D. from Brown University and has been a visiting scientist at IBM Watson labs. He has written or co-written over 20 popular computer books and articles for many developer magazines. He currently directs the program for Modern Visual Programming at the University of Connecticut.

Reader Feedback

Tell us what you think of this book excerpt.

 Very worth reading  Worth reading  Not worth reading

If you have other comments or ideas for future technical content, please type them here:

_______
1 As used on this web site, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.

[ This page was updated: 31-Jan-2000 ]
Products & APIs | Developer Connection | Docs & Training | Online Support
Community Discussion | Industry News | Solutions Marketplace | Case Studies
Glossary - Applets - Tutorial - Employment - Business & Licensing - Java Store - Java in the Real World
FAQ | Feedback | Map | A-Z Index
For more information on Java technology
and other software from Sun Microsystems, call:
(800) 786-7638
Outside the U.S. and Canada, dial your country's AT&T Direct Access Number first.
Sun Microsystems, Inc.
Copyright © 1995-2000 Sun Microsystems, Inc.
All Rights Reserved. Terms of Use. Privacy Policy.