Other Utility Classes

BitSet

This class maintains a set of bits that are identified by the value of an integer, like an array index. You can have over two billion individual bits in a set (if you have enough virtual memory), each of which can be queried, set, cleared, and so on. The bit set will increase dynamically as needed to accommodate extra bits you add.

public BitSet();  // constructor
public BitSet(int N);  // constructor for set of size N bits

public void or (BitSet s); // OR's one bit set against another.
public void set (int i); // sets bit number i.
public int size(); // returns the number of bits in the set.

Stack

The Stack class maintains a Last-In-First-Out stack of Objects. You can push (store) objects to arbitrary depth. The methods include:

public Object push(Object item);   // add to top of stack.

public Object pop();   // get top of stack.

In addition, there are three other methods not usually provided for stacks:

public boolean empty(); // nothing on the stack?

public Object peek();   // returns top Object without popping it.

public int search (Object o); // returns how far down the stack
// this object is (1 is at the top), or -1 if not found.

The original author of this class made an interesting mistake. He made Stack a subclass of Vector, so that he would get the vector behavior of allowing unbounded input. He failed to notice that it meant all the methods of Vector would be available in Stack—including inappropriate methods like removeElementAt() to pull something out of the middle of a vector. Therefore, Stack does not guarantee Last-In-First-Out behavior. Hans Rohnert from Germany pointed this out in email. As Hans put it, it is not true that Stack “is a” Vector, rather it should “have a” Vector in which to store.

The usual way to “hide” unwanted methods from a base class is to override them with private versions, empty versions, or versions that throw a run-time exception. In this case, Vector.removeElementAt(int)is final, and final methods can't be overriden. Never call removeElementAt()on your stack, and you'll stay out of trouble.

Some of these early 1.0 utility packages were written very quickly by skilled programmers who were more interested in getting the code working than achieving a perfect design. It's easier to find flaws in code than it is to write faultless software. Pointing out the occasional blemish is done in the spirit of learning, not as a criticism of the work of others.

The java.math API

Don't confuse the java.math package with the class java.lang.Math. Class java.lang.Math has trig operations on doubles. The java.math package described here contains three classes that support arithmetic with more decimal places than the hardware type double can provide. It also has an enum that describes rounding modes. The java.math package is slow (because it is implemented in software) but gives results of arbitrary accuracy.

The java.math package was added to JDK 1.1 for three reasons:

  • To be used in the java.security Digital Signature Algorithm interfaces.

  • To complete the support for all SQL types used in database programming and to allow arithmetic on types larger than long and double. If you do database programming, you'll be comfortable with the two java.math.BigDecimal and java.math.BigInteger classes, which can represent the SQL types DECIMAL and NUMERIC.

  • To do arithmetic on numbers of arbitrary size, even if you don't use cryptography or database programming.

As the names suggest, BigInteger deals with integers of unbounded size and BigDecimal deals with unbounded numbers with fractional parts. BigDecimal is essentially BigInteger with some extra code to keep track of the scale (where the decimal point is). If you want to manipulate a number that takes a megabyte to store all its decimal places, you can. BigInteger provides versions of all of Java's primitive integer operators and all relevant static methods from java.lang.Math. Additionally, BigInteger provides operations for modular arithmetic, greatest common divisor calculation, primality testing, prime generation, single-bit manipulation, and a few other odds and ends.

The following is an example of BigInteger used to perform a calculation that is listed in the 1989 Guinness Book of World Records under “Human Computer”:

BigInteger bi1 = new BigInteger("7686369774870");
BigInteger bi2 = new BigInteger("2465099745779");
bi1 = bi1.multiply(bi2);
System.out.println( "The value is "+ bi1 );

When compiled and run, the correct answer appears:

The value is 18947668177995426462773730

BigInteger naturally does it faster than the human record holder who took 28 seconds. The following is an example of BigDecimal used to round a number to four decimal places of precision:

BigDecimal bd1 = new BigDecimal( java.lang.Math.PI );
System.out.println( "The value is "+ bd1 );

int digsrightofradix = 4;
bd1 = bd1.setScale(digsrightofradix, BigDecimal.ROUND_HALF_UP);
System.out.println( "The value to 4 places is "+ bd1 );

When compiled and run, the following output appears:

The value is 3.141592653589793115997963468544185161590576171875
The value to 4 places is 3.1416

The true value is 3.1415926535 8979323846 2643383279 5028841971 693993751, so you can see that our value of pi is wrong in the 16th decimal place.

This is because we got the value from a double, and that's the limit on accuracy for doubles (refer back to Chapter 7 if you don't remember this). If we calculate pi from a formula using BigDecimal, we can get arbitrary precision.

Class BigDecimal also contains many other options for rounding numbers.

Random

This is a class to provide pseudo-random numbers. We call them pseudo-random rather than random because the source of bits is an algorithm. To the casual observer it looks like a random stream of bits, and for most applications we can pretend that they are. The numbers aren't really random, though, and sequences tend to get stuck in repetitive cycles after a large number of iterations.

If you just quickly want a random number between 0.0 and (just less than) 1.0, then the Math package has a random method, which is just a wrapper for instantiating Random one time and then supplying values. Use the following example to call the Random method:

double d = Math.random();  // returns value in range 0.0 .. 1.0

The Random class contains the following items:

public class java.util.Random implements java.io.Serializable {
     public java.util.Random();
     public java.util.Random(long);

     public boolean nextBoolean();
     public void nextBytes(byte[]);
     public int nextInt();
     public int nextInt(int);
     public long nextLong();

     public float nextFloat();
     public double nextDouble();

     // a Gaussian distribution has mean 0.0, standard deviation 1.0.
     public synchronized double nextGaussian();
     public synchronized void setSeed(long);
}

The nextGaussian() provides numbers symmetrically distributed around zero, and successively more unlikely to be picked the further away from zero you get. If we collected a group of these numbers and plotted them, they would form the shape of a bell curve. The algorithm used here for taking random values from a Gaussian distribution is from The Art of Computer Programming by Donald Knuth (Addison-Wesley, 1994: Section 3.4.1, Algorithm C).

You can instantiate Random with or without a seed. The following example uses a seed:

java.util.Random r = new java.util.Random(344L);

If you don't give Random a seed, it uses the current reading from the day and time clock (the millisecond part of this is going to be pretty close to random). If you choose to supply the seed, you will get the same series of random numbers every time you supply that same seed. This is useful in testing and debugging code.

To get a random int value in a certain range (for example, 0 to 5) to simulate the cast of a die, you would use the following:

int myturn = r.nextInt(6);

The method nextDouble returns a value between 0.0 and 1.0. To get a random double value in a certain range (for example, 0.0 to 100.0) to simulate a percentage, you would scale it up with multiplication:

double mypercent = r.nextDouble() * 100.0;

Properties

Java has a platform-independent way to communicate extra information at run-time to a program. Known as properties, these work like environment variables. Environment variables were shunned for being too platform-specific. A programmer can read the value of a property by calling getProperty() and passing an argument String for the property of interest:

String dir = System.getProperty("user.dir");

A long list of predefined properties appears in the file java/lang/System.java and in Table 19-6 on page 494. You can also define a new property on the command line when you invoke the program:

java -Drate=10.0  myprogram

Table 19-6. Predefined properties

Property Name

Explanation

java.version

java.vendor

java.vendor.url

java.home

java.class.version

java.class.path

os.name

os.arch

os.version

file.separator

path.separator

line.separator

user.name

user.home

user.dir

Version number of the Java system

Vendor-specific String

Vendor URL

Java installation directory

Java class version number

Java classpath

Operating System Name

Operating System Architecture

Operating System Version

File separator (“/” on Unix)

Path separator (":" on Unix)

Line separator (" " on Unix)

User account name

User home directory

User's current working directory

That value “10.0” will be returned as a String when querying the property “rate.”

String r = System.getProperty("rate");

It can be converted to a floating-point number and used as a value in the program. In this case, it's an alternative to a command line argument, but with the advantage that its' value is visible everywhere, not just in main.

Predefined properties lists the predefined properties guaranteed to have a value on every Java client. Others also exist.

Most programs don't need to access these properties at all. But if they do, it's nice to be able to do it in a platform-independent way.

The java.util.Properties class

You will be happy to hear that there is a java.util class to help you read in and process properties. The java.util.Properties class is just a subclass of java.util.Hashtable with a few extra methods added. The concept of properties also exists in other languages, such as Lisp and Forth. The Java system comes with a whole set of predefined properties holding information about the implementation.

This utility class has two purposes: it allows a property table to be read in and written out via streams and it allows programmers to search more than one property table with a single command. If you don't need either of these benefits, you could use a HashMap instead of a Properties table.

Typical methods include the following:

public String getProperty(String key);

public synchronized void load(InputStream in)
     throws IOException;
// reads key/value pairs in from a stream, stores them in this

public synchronized void save(OutputStream out, String header);
// writes the key/value pairs out as text
// the header is just a comment String you provide to label
// the property table. The current date is also appended.

To put entries in a Properties object, use the put(Object key, Object element) method inherited from HashTable. So that you don't feel obliged to start adding to the predefined system property table, there's a feature that allows you to provide an existing properties table to a constructor. This creates an empty properties list that you can populate. Whenever you do a getProperty, it will search your table. If nothing is found, it will go on to search the table provided to the constructor. Here is an example:

Properties sp = System.getProperties();
Properties mytable = new Properties(sp);
mytable.list(System.out);

The first line gets the standard predefined properties table. The second line piggybacks it onto a second Properties table that we create and can fill with a call, such as mytable.put (propertyname, propertyvalue). When we do a lookup in mytable, it will look first in mytable and then in the system properties table. The third line prints mytable (intended for debugging, but it's not clear why you can't just use the save() method). The method public String getProperty(String key, String default) will return the default String if there is no entry for this key in the table.

Note on the Java native interface

image

The Java Native Interface is an API that allows you to make calls into C and C++ programs from Java. You can also make calls into any other programming language that follows the C calling and linking conventions. Non-Java code is referred to as native code; therefore, it is a native interface.

If you use the JNI, you tie your code to a single platform and operating system, losing a major benefit of Java. The JNI should be used only as a last resort. Most programs don't need it and won't use it.

Readers who want to put JNI into practice can browse the JavaSoft web page for an introduction to JNI. Use the search facility on the home page at java.sun.com, and look for “JNI.” Avoid the use of native methods if you can.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.220.83