Web Development and Design | Tutorial for Java, PHP, HTML, Javascript: java-programming-for-beginners

Web Development and Design | Tutorial for Java, PHP, HTML, Javascript: java-programming-for-beginners
Showing posts with label java-programming-for-beginners. Show all posts
Showing posts with label java-programming-for-beginners. Show all posts

Java Converting Epoch Seconds to DMYHMS

Java Converting Epoch Seconds to DMYHMS

Problem

You need to convert a number of seconds since 1970 into a Date .

Solution

Just use the Date constructor.

Explained

“The Epoch” is the beginning of time as far as modern operating systems go. Unix
time, and some versions of Windows time, count off inexorably the seconds since
the epoch. On systems that store this in a 32-bit integer, time is indeed running out.
Let’s say we wanted to find out when the Unix operating system, whose 32-bit ver-
sions use a 32-bit date, will get into difficulty. We take a 32-bit integer of all ones,
and construct a Date around it. The Date constructor needs the number of millisec-
onds since 1970, so we multiply by 1,000:

/** When does the UNIX date get into trouble? */
public class Y2038 {
public static void main(String[] a) {
// This should yield 2038AD, the hour of doom for the
// last remaining 32-bit UNIX systems (there will be
// millions of 64-bit UNIXes by then).
long expiry = 0x7FFFFFFFL;
System.out.println("32-bit UNIX expires on " +
Long.toHexString(expiry) + " or " +
new java.util.Date(expiry * 1000));
}
}


Sure enough, the program reports that 32-bit Unixes will expire in the year 2038 (you might think I knew that in advance if you were to judge by the name I gave the class; in fact, my web site has carried the Y2038 warning to Unix users for several years now). At least Unix system managers have more warning than most of the gen- eral public had for the original Y2K problem.

> java Y2038
32-bit UNIX expires on 7fffffff or Mon Jan 18 22:14:07 EST 2038
>

At any rate, if you need to convert seconds since 1970 to a date, you know how.

Java Parsing Strings into Dates

Java Parsing Strings into Dates

Problem

You need to convert user input into Date or Calendar objects.

Solution

Use a DateFormat .

Explained

The DateFormat class introduced in Recipe 6.2 has some additional methods, notably
parse( ) , which tries to parse a string according to the format stored in the given
DateFormat object:

// DateParse1.java
SimpleDateFormat formatter
= new SimpleDateFormat ("yyyy-MM-dd");
String input = args.length == 0 ? "1818-11-11" : args[0];
System.out.print(input + " parses as ");
Date t;
try {
t = formatter.parse(input);
System.out.println(t);
} catch (ParseException e) {
System.out.println("unparseable using " + formatter);
}

This program parses any date back to Year Zero and well beyond Year 2000. What if the date is embedded in an input string? You could, of course, use the string’s substring( ) method to extract it, but there is an easier way. The ParsePosition object from java.text is designed to represent (and track) the posi- tion of an imaginary cursor in a string. Suppose we have genealogical data with input strings representing the times of a person’s life:

BD: 1913-10-01 Vancouver, B.C.
DD: 1983-06-06 Toronto, ON

This lists one person’s birth date (BD) and place, and death date (DD) and place. We can parse these using String.indexOf(' ') to find the space after the : character, DateFormat parse( ) to parse the date, and String.substring( ) to get the city and other geographic information. Here’s how:

// DateParse2.java
SimpleDateFormat formatter =
new SimpleDateFormat ("yyyy-MM-dd");
String input[] = {
"BD: 1913-10-01 Vancouver, B.C.",
"MD: 1948-03-01 Ottawa, ON",
"DD: 1983-06-06 Toronto, ON" };
for (int i=0; i<input.length; i++) {
String aLine = input[i];
String action;
switch(aLine.charAt(0)) {
case 'B': action = "Born"; break;
case 'M': action = "Married"; break;
case 'D': action = "Died"; break;
// others...
default: System.err.println("Invalid code in " + aLine);
continue;
}
int p = aLine.indexOf(' ');
ParsePosition pp = new ParsePosition(p);
Date d = formatter.parse(aLine, pp);
if (d == null) {
System.err.println("Invalid date in " + aLine);
continue;
}
String location = aLine.substring(pp.getIndex( ));
System.out.println(
action + " on " + d + " in " + location);
}

This works like I said it would:

Born on Wed Oct 01 00:00:00 PDT 1913 in Vancouver, B.C.
Married on Mon Mar 01 00:00:00 PST 1948 in Ottawa, ON
Died on Mon Jun 06 00:00:00 PDT 1983 in Toronto, ON

Note that the polymorphic form of parse( ) that takes one argument throws a ParseException if the input cannot be parsed, while the form that takes a ParsePosition as its second argument returns null to indicate failure.

Java Converting YMDHMS to a Calendar or Epoch Seconds

Java Converting YMDHMS to a Calendar
or Epoch Seconds

Problem

You have year, month, day, hour, minute, and maybe even seconds, and you need to
convert it to a Calendar or a Date .

Solution

Use the Calendar class’s set(y,m,d,h,m[,s]) method, which allows you to set the
date/time fields to whatever you wish. Note that when using this form and providing
your own numbers, or when constructing either a Date or a GregorianCalendar
object, the month value is zero-based while all the other values are true-origin. Pre-
sumably, this is to allow you to print the month name from an array without having
to remember to subtract one, but it is still confusing.

// GregCalDemo.java
GregorianCalendar d1 = new GregorianCalendar(1986, 04, 05); // May 5
GregorianCalendar d2 = new GregorianCalendar( );
// today
Calendar d3 = Calendar.getInstance( );
// today
System.out.println("It was then " + d1.getTime( ));
System.out.println("It is now " + d2.getTime( ));
System.out.println("It is now " + d3.getTime( ));
d3.set(Calendar.YEAR, 1915);
d3.set(Calendar.MONTH, Calendar.APRIL);
d3.set(Calendar.DAY_OF_MONTH, 12);
System.out.println("D3 set to " + d3.getTime( ));

This prints the dates as shown:

It was then Mon May 05 00:00:00 EDT 1986
It is now Thu Mar 25 16:36:07 EST 2004
It is now Thu Mar 25 16:36:07 EST 2004
D3 set to Mon Apr 12 16:36:07 EST 1915

Java Representing Dates in Other Epochs

Java Representing Dates in Other Epochs

Problem

You need to deal with dates in a form other than the Gregorian Calendar used in the
Western world.

Solution

Download the IBM calendar classes.

Explained

The only nonabstract Calendar subclass is the GregorianCalendar , as mentioned pre-
viously. However, other calendar classes do exist. IBM has a set of calendars—
Hebrew, Islamic, Buddhist, Japanese, and even an Astronomical Calendar class—that
covers most of the rest of the world. This work has been open sourced and is now
part of a project called International Components for Unicode for Java.

The calendar classes in ICU4J work in a similar fashion to the standard
GregorianCalendar class, but they have constants for month names and other infor-
mation relevant to each particular calendar. They are not subclassed from java.util.
Calendar , however, so they must be referred to by their full class name:

import
import
import
import
java.util.Locale;
com.ibm.icu.util.Calendar;
java.text.DateFormat;
com.ibm.icu.util.IslamicCalendar;
public class IBMCalDemo {
public static void main(String[] args) {
Locale ar_loc = new Locale("ar");
Calendar c = new com.ibm.icu.util.IslamicCalendar( );
DateFormat d = DateFormat.getDateInstance(DateFormat.LONG, ar_loc);
System.out.println(d.format(c.getTime( )));
}
}

I can’t include the textual output because of font limitations.

Java Finding Today’s Date

Java Finding Today’s Date

Problem

You want to find today’s date.

Solution

Use a Date object’s toString( ) method.

Explained

The quick and simple way to get today’s date and time is to construct a Date object
with no arguments in the constructor call, and call its toString( ) method:

// Date0.java
System.out.println(new java.util.Date( ));

However, for reasons just outlined, we want to use a Calendar object. Just use Calendar.getInstance( ).getTime( ) , which returns a Date object (even though the name makes it seem like it should return a Time value * ) and prints the resulting Date object, using its toString( ) method or preferably a DateFormat object. You might be tempted to construct a GregorianCalendar object, using the no-argument construc- tor, but if you do this, your program will not give the correct answer when non- Western locales get Calendar subclasses of their own (which might occur in some future release of Java). The static factory method Calendar.getInstance( ) returns a localized Calendar subclass for the locale you are in. In North America and Europe it will likely return a GregorianCalendar , but in other parts of the world it might (some- day) return a different kind of Calendar . Do not try to use a GregorianCalendar ’s toString( ) method; the results are truly impressive, but not very interesting. Sun’s implementation prints all its internal state information; Kaffe’s inherits Object ’s toString( ) , which just prints the class name and the hashcode. Neither is useful for our purposes.

C> java Date1
java.util.
GregorianCalendar[time=932363506950,areFieldsSet=true,areAllFieldsSet=true,lenient=tr
ue,zone=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-
28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=3,sta
rtDay=1,startDayOfWeek=1,startTime=7200000,endMode=2,endMonth=9,endDay=-
1,endDayOfWeek=1,endTime=7200000],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEA
R=1999,MONTH=6,WEEK_OF_YEAR=30,WEEK_OF_MONTH=4,DAY_OF_MONTH=18,DAY_OF_YEAR=199,DAY_
OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=10,HOUR_OF_
DAY=22,MINUTE=51,SECOND=46,MILLISECOND=950,ZONE_OFFSET=-28800000,DST_OFFSET=3600000]

Calendar ’s getTime( ) returns a Date object, which can be passed to println( ) to print today’s date (and time) in the traditional (but non-localized) format:

/ Date2.java
System.out.println(Calendar.getInstance( ).getTime( ));

Java Program: TempConverter

Java Program: TempConverter


The program shown in Example prints a table of Fahrenheit temperatures (still
used in daily life weather reporting in the United States) and the corresponding Celsius temperatures (used in science everywhere, and in daily life in most of the world).

Example TempConverter.java
import java.text.*;
/* Print a table of Fahrenheit and Celsius temperatures
*/
public class TempConverter {
public static void main(String[] args) {
TempConverter t = new TempConverter( );
t.start( );
t.data( );
t.end( );
}
protected void start( ) {
}
protected void data( ) {
for (int i=-40; i<=120; i+=10) {
float c = (i-32)*(5f/9);
print(i, c);
}
}
protected void print(float f, float c) {
System.out.println(f + " " + c);
}
protected void end( ) {
}
}


This works, but these numbers print with about 15 digits of (useless) decimal frac- tions! The second version of this program subclasses the first and uses a DecimalFormat to control the formatting of the converted temperatures

Example TempConverter2.java
import java.text.*;
/* Print a table of fahrenheit and celsius temperatures, a bit more neatly.
*/
public class TempConverter2 extends TempConverter {
protected DecimalFormat df;
public static void main(String[] args) {
TempConverter t = new TempConverter2( );
t.start( );
t.data( );
t.end( );
}
// Constructor
public TempConverter2( ) {
df = new DecimalFormat("#0.00");
}
protected void print(float f, float c) {
System.out.println(f + " " + df.format(c));
}
protected void start( ) {
System.out.println("Fahr
}
Centigrade.");
protected void end( ) {
System.out.println("-------------------");
}
}

This works, and the results are better than the first version’s, but still not right:

C:\javasrc\numbers>java
Fahr
Centigrade.
-40.00 -40.00
-30.00 -34.44
-20.00 -28.89
-10.00 -23.33
0.00 -17.78
10.00 -12.22
20.00 -6.67
30.00 -1.11
40.00 4.44
50.00 10.00
60.00 15.56
70.00 21.11
80.00 26.67
90.00 32.22
100.00 37.78
110.00 43.33
120.00 48.89
TempConverter2


It would look neater if we lined up the decimal points, but Java had nothing in its standard API for doing this. This is deliberate! They wanted to utterly break the ties with the ancient IBM 1403 line printers and similar monospaced devices such as typewriters, “dumb” terminals, * and DOS terminal windows. However, with a bit of simple arithmetic, the FieldPosition from Recipe 5.11 can be used to figure out how many spaces need to be prepended to line up the columns; the arithmetic is done in print( ) , and the spaces are put on in prependSpaces( ) . The result is much prettier:

C:\javasrc\numbers>java
Fahr
Centigrade.
-40
-40
-30
-34.444
-20
-28.889
-10
-23.333
0
-17.778
10
-12.222
20
-6.667
TempConverter30
30
-1.111
40
4.444
50
10
60
15.556
70
21.111
80
26.667
90
32.222
100
37.778
110
43.333
120
48.889
-------------------

And the code is only ten lines longer!

import java.text.*;
/* Print a table of Fahrenheit and Celsius temperatures, with decimal
* points lined up.
*/
public class TempConverter3 extends TempConverter2 {
protected FieldPosition fp;
protected DecimalFormat dff;
public static void main(String[] args) {
TempConverter t = new TempConverter3( );
t.start( );
t.data( );
t.end( );
}
// Constructor
public TempConverter3( ) {
super( );
dff = new DecimalFormat("##.#");
fp = new FieldPosition(NumberFormat.INTEGER_FIELD);
}
protected void print(float f, float c) {
String fs = dff.format(f, new StringBuffer( ), fp).toString( );
fs = prependSpaces(4 - fp.getEndIndex( ), fs);
String cs = df.format(c, new StringBuffer( ), fp).toString( );
cs = prependSpaces(4 - fp.getEndIndex( ), cs);
System.out.println(fs + "
" + cs);
}
protected String prependSpaces(int n, String s) {
String[] res = {
"", " ", " ", "
", "
", "
"
};
if (n<res.length)
return res[n] + s;
throw new IllegalStateException("Rebuild with bigger \"res\" array.");
}
}

Java Handling Very Large Numbers

Java Handling Very Large Numbers


Problem

You need to handle integer numbers larger than Long.MAX_VALUE or floating-point val-
ues larger than Double.MAX_VALUE .

Solution

Use the BigInteger or BigDecimal values in package java.math :

// BigNums.java
System.out.println("Here's Long.MAX_VALUE: " + Long.MAX_VALUE);
BigInteger bInt = new BigInteger("3419229223372036854775807");
System.out.println("Here's a bigger number: " + bInt);
System.out.println("Here it is as a double: " + bInt.doubleValue( ));

Note that the constructor takes the number as a string. Obviously you couldn’t just type the numeric digits since by definition these classes are designed to represent numbers larger than will fit in a Java long .

Explained 

Both BigInteger and BigDecimal objects are immutable; that is, once constructed, they always represent a given number. That said, a number of methods return new objects that are mutations of the original, such as negate( ) , which returns the nega- tive of the given BigInteger or BigDecimal . There are also methods corresponding to most of the Java language built-in operators defined on the base types int / long and float / double . The division method makes you specify the rounding method; consult a book on numerical analysis for details. Example is a simple stack-based calcula- tor using BigDecimal as its numeric data type.

Example BigNumCalc
import java.math.BigDecimal;
import java.util.Stack;
/** A trivial reverse-polish stack-based calculator for big numbers */
public class BigNumCalc {
/** an array of Objects, simulating user input */
public static Object[] testInput = {
new BigDecimal("3419229223372036854775807.23343"),
new BigDecimal("2.0"),
"*",
};
public static void main(String[] args) {
BigNumCalc calc = new BigNumCalc( );
System.out.println(calc.calculate(testInput));
}

Stack s = new Stack( );
public BigDecimal calculate(Object[] input) {
BigDecimal tmp;
for (int i = 0; i < input.length; i++) {
Object o = input[i];
if (o instanceof BigDecimal)
s.push(o);
else if (o instanceof String) {
switch (((String)o).charAt(0)) {
// + and * are commutative, order doesn't matter
case '+':
s.push(((BigDecimal)s.pop()).add((BigDecimal)s.pop( )));
break;
case '*':
s.push(((BigDecimal)s.pop()).multiply((BigDecimal)s.pop( )));
break;
// - and /, order *does* matter
case '-':
tmp = (BigDecimal)s.pop( );
s.push(((BigDecimal)s.pop( )).subtract(tmp));
break;
case '/':
tmp = (BigDecimal)s.pop( );
s.push(((BigDecimal)s.pop( )).divide(tmp,
BigDecimal.ROUND_UP));
break;
default:
throw new IllegalStateException("Unknown OPERATOR popped");
}
} else {
throw new IllegalStateException("Syntax error in input");
}
}
return (BigDecimal)s.pop( );
}
}

Running this produces the expected (very large) value:

> jikes +E -d . BigNumCalc.java
> java BigNumCalc
6838458446744073709551614.466860
>

The current version has its inputs hard-coded, as does the JUnit test program, but in real life you can use regular expressions to extract words or operators from an input stream (as in Recipe 4.5), or you can use the StreamTokenizer approach of the simple calculator (Recipe 10.4). The stack of numbers is maintained using a java.util. Stack (Recipe 7.14). BigInteger is mainly useful in cryptographic and security applications. Its method isProbablyPrime( ) can create prime pairs for public key cryptography. BigDecimal might also be useful in computing the size of the universe.

Java Taking Logarithms

Java Taking Logarithms

Problem

You need to take the logarithm of a number.

Solution

For logarithms to base e , use java.lang.Math ’s log( ) function:

// Logarithm.java
double someValue;
// compute someValue...
double log_e = Math.log(someValue);

For logarithms to other bases, use the identity that:

                  loge ( x )
                     
logn ( x ) = -------------------
                      loge ( n )

                       

where x is the number whose logarithm you want, n is any desired base, and e is the natural logarithm base. I have a simple LogBase class containing code that imple- ments this functionality:

// LogBase.java
public static double log_base(double base, double value) {
return Math.log(value) / Math.log(base);
}

Explained 

My log_base function allows you to compute logs to any positive base. If you have to perform a lot of logs to the same base, it is more efficient to rewrite the code to cache the log(base) once. Here is an example of using log_base :

// LogBaseUse.java
public static void main(String argv[]) {
double d = LogBase.log_base(10, 10000);
System.out.println("log10(10000) = " + d);
}
C:> java LogBaseUse
log10(10000) = 4.0

Java Calculating Trigonometric Functions

Java Calculating Trigonometric Functions

Problem

You need to compute sine, cosine, and other trigonometric functions.

Solution

Use the trig functions in java.lang.Math . Like java.lang.Math.random( ) , all the
methods of the Math class are static, so no Math instance is necessary. This makes
sense, as none of these computations maintains any state. Note that the arguments
for trigonometric functions are in radians, not in degrees. Here is a program that
computes a few (mostly) trigonometric values and displays the values of e and PI that
are available in the math library:

// Trig.java
System.out.println("Java's PI is " + Math.PI);
System.out.println("Java's e is " + Math.E);
System.out.println("The cosine of 1.1418 is " + Math.cos(1.1418));

The java.lang.StrictMath class, introduced in JDK 1.3, is intended to perform the same operations as java.lang.Math but with greater cross-platform repeatability.

Java Generating Better Random Numbers

Java Generating Better Random Numbers

Problem

You need to generate better random numbers.

Solution

Construct a java.util.Random object (not just any old random object) and call its
next*( ) methods. These methods include nextBoolean( ) , nextBytes( ) (which fills
the given array of bytes with random values), nextDouble( ) , nextFloat( ) , nextInt( ) ,
and nextLong( ) . Don’t be confused by the capitalization of Float , Double , etc. They
return the primitive types boolean , float , double , etc., not the capitalized wrapper
objects. Clear enough? Maybe an example will help:

// Random2.java
// java.util.Random methods are non-static, so need to construct
Random r = new Random( );
for (int i=0; i<10; i++)
System.out.println("A double from java.util.Random is " + r.nextDouble( ));
for (int i=0; i<10; i++)
System.out.println("An integer from java.util.Random is " + r.nextInt( ));

You can also use the java.util.Random nextGaussian( ) method, as shown next. The nextDouble( ) methods try to give a “flat” distribution between 0 and 1.0, in which each value has an equal chance of being selected. A Gaussian or normal distribution is a bell-curve of values from negative infinity to positive infinity, with the majority of the values around zero (0.0).

// Random3.java
Random r = new Random( );
for (int i=0; i<10; i++)
System.out.println("A gaussian random double is " + r.nextGaussian( ));

See Also

The Javadoc documentation for java.util.Random , and the warning in the Introduc- tion about pseudo-randomness versus real randomness. For cryptographic use, see class java.security.SecureRandom , which provides crypto- graphically strong pseudo-random number generators (PRNG).

Java Formatting with Correct Plurals

Java Formatting with Correct Plurals

Problem

You’re printing something like "We used " + n + " items" , but in English, “We used 1
items” is ungrammatical. You want “We used 1 item.”

Solution

Use a ChoiceFormat or a conditional statement.

Use Java’s ternary operator ( cond ? trueval : falseval ) in a string concatenation.
Both zero and plurals get an “s” appended to the noun in English, so we test for n==1 .

// FormatPlurals.java
public static void main(String argv[]) {
report(0);
report(1);
report(2);
}
/** report -- using conditional operator */
public static void report(int n) {
System.out.println("We used " + n + " item" + (n==1?"":"s"));
}

Does it work?

$ java FormatPlurals
We used 0 items
We used 1 item
We used 2 items
$

The final println statement is short for:

if (n==1)
System.out.println("We used " + n + " item");
else
System.out.println("We used " + n + " items");

This is a lot longer, in fact, so the ternary conditional operator is worth learning. The ChoiceFormat is ideal for this. It is actually capable of much more, but here I’ll show only this simplest use. I specify the values 0, 1, and 2 (or more), and the string values to print corresponding to each number. The numbers are then formatted according to the range they fall into:

import java.text.*;
/**
* Format a plural correctly, using a ChoiceFormat.
*/
public class FormatPluralsChoice extends FormatPlurals {
static double[] limits = { 0, 1, 2 };
static String[] formats = { "items", "item", "items"};
static ChoiceFormat myFormat = new ChoiceFormat(limits, formats);
/** report -- using conditional operator */
public static void report(int n) {
System.out.println("We used " + n + " " + myFormat.format(n));
}
public static void main(String[] argv) {
report(0);
report(1);
report(2);
}
}

This generates the same output as the basic version. It is slightly longer, but more general, and lends itself better to internationalization.

Java Working with Roman Numerals

Java Working with Roman Numerals

Problem

You need to format numbers as Roman numerals. Perhaps you’ve just written the
next Titanic or Star Wars episode and you need to get the copyright date correct. Or,
on a more mundane level, you need to format page numbers in the front matter of a
book.

Solution

Use my RomanNumberFormat class:

// RomanNumberSimple.java
RomanNumberFormat nf = new RomanNumberFormat( );
int year = Calendar.getInstance( ).get(Calendar.YEAR);
System.out.println(year + " -> " + nf.format(year));

The use of Calendar to get the current year is explained in Recipe 6.1. Running RomanNumberSimple looks like this:

+ jikes +E -d . RomanNumberSimple.java
+ java RomanNumberSimple
2004 -> MMIV

Explained

Nothing in the standard API formats Roman numerals. However, the java.text. Format class is designed to be subclassed for precisely such unanticipated purposes, so I have done just that and developed a class to format numbers as Roman numer- als. Here is a better and complete example program of using it to format the current year. I can pass a number of arguments on the command line, including a "-" where I want the year to appear (note that these arguments are normally not quoted; the "-" must be an argument all by itself, just to keep the program simple). I use it as follows:

$ java RomanYear
Copyright (c) - Ian Darwin
Copyright (c) MMIV Ian Darwin
$

The code for the RomanYear program is simple, yet it correctly puts spaces around the arguments:

import java.util.*;
/** Print the current year in Roman Numerals */
public class RomanYear {
public static void main(String[] argv) {
RomanNumberFormat rf = new RomanNumberFormat( );
Calendar cal = Calendar.getInstance( );
int year = cal.get(Calendar.YEAR);
// If no arguments, just print the year.
if (argv.length == 0) {
System.out.println(rf.format(year));
return;
}
// Else a micro-formatter: replace "-" arg with year, else print.
for (int i=0; i<argv.length; i++) {
if (argv[i].equals("-"))
System.out.print(rf.format(year));
else
System.out.print(argv[i]);
// e.g., "Copyright"
System.out.print(' ');
}
System.out.println( );
}
}

Now here’s the code for the RomanNumberFormat class. I did sneak in one additional class, java.text.FieldPosition . A FieldPosition simply represents the position of one numeric field in a string that has been formatted using a variant of NumberFormat. format( ) . You construct it to represent either the integer part or the fraction part (of course, Roman numerals don’t have fractional parts). The FieldPosition methods getBeginIndex( ) and getEndIndex( ) indicate where in the resulting string the given field wound up. Example is the class that implements Roman number formatting. As the com- ments indicate, the one limitation is that the input number must be less than 4,000.

Example RomanNumberFormat.java

import java.text.*;
import java.util.*;
/**
* Roman Number class. Not localized, since Latin's a Dead Dead Language
* and we don't display Roman Numbers differently in different Locales.
* Filled with quick-n-dirty algorithms.
*/
public class RomanNumberFormat extends Format {
/** Characters used in "Arabic to Roman", that is, format( ) methods. */
static char A2R[][] = {
{ 0, 'M' },
{ 0, 'C', 'D', 'M' },
{ 0, 'X', 'L', 'C' },
{ 0, 'I', 'V', 'X' },
};

/** Format a given double as a Roman Numeral; just truncate to a
* long, and call format(long).
*/
public String format(double n) {
return format((long)n);
}
/** Format a given long as a Roman Numeral. Just call the
* three-argument form.
*/
public String format(long n) {
if (n <= 0 || n >= 4000)
throw new IllegalArgumentException(n + " must be > 0 && < 4000");
StringBuffer sb = new StringBuffer( );
format(new Integer((int)n), sb, new FieldPosition(NumberFormat.INTEGER
FIELD));
return sb.toString( );
}

/* Format the given Number as a Roman Numeral, returning the
* Stringbuffer (updated), and updating the FieldPosition.
* This method is the REAL FORMATTING ENGINE.
* Method signature is overkill, but required as a subclass of Format.
*/
public StringBuffer format(Object on, StringBuffer sb, FieldPosition fp) {
if (!(on instanceof Number))
throw new IllegalArgumentException(on + " must be a Number object");

if (fp.getField( ) != NumberFormat.INTEGER_FIELD)
throw new IllegalArgumentException(fp +
" must be FieldPosition(NumberFormat.INTEGER_FIELD");
int n = ((Number)on).intValue( );
// TODO check for in range here
// First, put the digits on a tiny stack. Must be 4 digits.
for (int i=0; i<4; i++) {
int d=n%10;
push(d);
// System.out.println("Pushed " + d);
n=n/10;
}

// Now pop and convert.
for (int i=0; i<4; i++) {
int ch = pop( );
// System.out.println("Popped " + ch);
if (ch==0)
continue;
else if (ch <= 3) {
for(int k=1; k<=ch; k++)
sb.append(A2R[i][1]); // I
}
else if (ch == 4) {
sb.append(A2R[i][1]);
// I
sb.append(A2R[i][2]);
// V
}
else if (ch == 5) {
sb.append(A2R[i][2]);
// V
}
else if (ch <= 8) {
sb.append(A2R[i][2]);
// V
for (int k=6; k<=ch; k++)
sb.append(A2R[i][1]);
// I
}
else { // 9
sb.append(A2R[i][1]);
sb.append(A2R[i][3]);
}
}
// fp.setBeginIndex(0);
// fp.setEndIndex(3);
return sb;
}

/** Parse a generic object, returning an Object */
public Object parseObject(String what, ParsePosition where) {
throw new IllegalArgumentException("Parsing not implemented");
// TODO PARSING HERE
// return new Long(0);
}
/* Implement a toy stack */
protected int stack[] = new int[10];
protected int depth = 0;
/* Implement a toy stack */
protected void push(int n) {
stack[depth++] = n;
}
/* Implement a toy stack */
protected int pop( ) {
return stack[--depth];
}
}

Several of the public methods are required because I wanted it to be a subclass of Format , which is abstract. This accounts for some of the complexity, like having three different format methods. Note that the parseObject( ) method is also required, but we don’t actually implement parsing in this version. This is left as the usual exercise for the reader.

Java Rounding Floating-Point Numbers

Java Rounding Floating-Point Numbers

Problem

You need to round floating-point numbers to integers or to a particular precision.

Solution

If you simply cast a floating value to an integer value, Java truncates the value. A
value like 3.999999 cast to an int or long becomes 3, not 4. To round floating-point
numbers properly, use Math.round( ) . It has two forms: if you give it a double , you get
a long result; if you give it a float , you get an int .

What if you don’t like the rounding rules used by round ? If for some bizarre reason
you wanted to round numbers greater than 0.54 instead of the normal 0.5, you could
write your own version of round( ) :

/*
* Round floating values to integers.
* @Return the closest int to the argument.
* @param d A non-negative values to be rounded.
*/
static int round(double d) {
if (d < 0) {
throw new IllegalArgumentException("Value must be non-negative");
}
int di = (int)Math.floor(d);
// integral value below (or ==) d
if ((d - di) > THRESHOLD) {
return di + 1;
} else {
return di;
}
}

If you need to display a number with less precision than it normally gets, you proba- bly want to use a DecimalFormat object or a Formatter object.

Java Comparing Floating-Point Numbers

Java Comparing Floating-Point Numbers

Problem

You want to compare two floating-point numbers for equality.

Solution

Based on what we’ve just discussed, you probably won’t just go comparing two
floats or doubles for equality. You might expect the floating-point wrapper classes,

Float and Double , to override the equals( ) method, which they do. The equals( )
method returns true if the two values are the same bit for bit, that is, if and only if
the numbers are the same or are both NaN . It returns false otherwise, including if the
argument passed in is null, or if one object is +0.0 and the other is –0.0.

If this sounds weird, remember that the complexity comes partly from the nature of
doing real number computations in the less-precise floating-point hardware, and
partly from the details of the IEEE Standard 754, which specifies the floating-point
functionality that Java tries to adhere to, so that underlying floating-point processor
hardware can be used even when Java programs are being interpreted.

To actually compare floating-point numbers for equality, it is generally desirable to
compare them within some tiny range of allowable differences; this range is often
regarded as a tolerance or as epsilon. Example shows an equals( ) method you
can use to do this comparison, as well as comparisons on values of NaN . When run, it
prints that the first two numbers are equal within epsilon:

$ java FloatCmp
True within epsilon 1.0E-7
$

Example. FloatCmp.java
}/**
* Floating-point comparisons.
*/
public class FloatCmp {
final static double EPSILON = 0.0000001;
public static void main(String[] argv) {
double da = 3 * .3333333333;
double db = 0.99999992857;
// Compare two numbers that are expected to be close.
if (da == db) {
System.out.println("Java considers " + da + "==" + db);
// else compare with our own equals method
} else if (equals(da, db, 0.0000001)) {
System.out.println("True within epsilon " + EPSILON);
} else {
System.out.println(da + " != " + db);
}
// Show that comparing two NaNs is not a good idea:
double d1 = Double.NaN;
double d2 = Double.NaN;
if (d1 == d2)
System.err.println("Comparing two NaNs incorrectly returns true.");
if (!new Double(d1).equals(new Double(d2)))
System.err.println("Double(NaN).equal(NaN) incorrectly returns false.");
}

/** Compare two doubles within a given epsilon */
public static boolean equals(double a, double b, double eps) {
if (a==b) return true;
// If the difference is less than epsilon, treat as equal.
return Math.abs(a - b) < eps;
}
/** Compare two doubles, using default epsilon */
public static boolean equals(double a, double b) {
if (a==b) return true;
// If the difference is less than epsilon, treat as equal.
return Math.abs(a - b) < EPSILON * Math.max(Math.abs(a), Math.abs(b));
}
}

Note that neither of the System.err messages about “incorrect returns” prints. The point of this example with NaN s is that you should always make sure values are not NaN before entrusting them to Double.equals( ).

Java Ensuring the Accuracy of Floating-Point Numbers

Java Ensuring the Accuracy of Floating-Point
Numbers

Problem

You want to know if a floating-point computation generated a sensible result.

Solution

Compare with the INFINITY constants, and use isNaN( ) to check for “not a number.”
Fixed-point operations that can do things like divide by zero result in Java notifying
you abruptly by throwing an exception. This is because integer division by zero is
considered a logic error.

Floating-point operations, however, do not throw an exception because they are
defined over an (almost) infinite range of values. Instead, they signal errors by pro-
ducing the constant POSITIVE_INFINITY if you divide a positive floating-point num-
ber by zero, the constant NEGATIVE_INFINITY if you divide a negative floating-point
value by zero, and NaN (Not a Number), if you otherwise generate an invalid result.
Values for these three public constants are defined in both the Float and the Double wrapper classes.

The value NaN has the unusual property that it is not equal to itself,
that is, NaN != NaN . Thus, it would hardly make sense to compare a (possibly sus-
pect) number against NaN , because the expression:

x == NaN

can never be true. Instead, the methods Float.isNaN(float) and Double. isNaN(double) must be used:

// InfNaN.java
public static void main(String argv[]) {
double d = 123;
double e = 0;
if (d/e == Double.POSITIVE_INFINITY)
System.out.println("Check for POSITIVE_INFINITY works");
double s = Math.sqrt(-1);
if (s == Double.NaN)
System.out.println("Comparison with NaN incorrectly returns true");
if (Double.isNaN(s))
System.out.println("Double.isNaN( ) correctly returns true");
}

Note that this, by itself, is not sufficient to ensure that floating-point calculations have been done with adequate accuracy. For example, the following program dem- onstrates a contrived calculation—Heron’s formula for the area of a triangle—both in float and in double . The double values are correct, but the floating-point value comes out as zero due to rounding errors. This happens because, in Java, operations involving only float values are performed as 32-bit calculations. Related languages such as C automatically promote these to double during the computation, which can eliminate some loss of accuracy.

/** Compute the area of a triangle using Heron's Formula.
* Code and values from Prof W. Kahan and Joseph D. Darcy.
* See http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf.
* Derived from listing in Rick Grehan's Java Pro article (October 1999).
* Simplified and reformatted by Ian Darwin.
*/
public class Heron {
public static void main(String[] args) {
// Sides for triangle in float
float af, bf, cf;
float sf, areaf;
// Ditto in double
double ad, bd, cd;
double sd, aread;
af
bf
cf
//Area of triangle in float
= 12345679.0f;
= 12345678.0f;
= 1.01233995f;
sf = (af+bf+cf)/2.0f;
areaf = (float)Math.sqrt(sf * (sf - af) * (sf - bf) * (sf - cf));
System.out.println("Single precision: " + areaf);
//
ad
bd
cd
Area of triangle in double
= 12345679.0;
= 12345678.0;
= 1.01233995;
sd = (ad+bd+cd)/2.0d;
aread =
Math.sqrt(sd * (sd - ad) * (sd - bd) * (sd - cd));
System.out.println("Double precision: " + aread);
}
}

Let’s run it. To ensure that the rounding is not an implementation artifact, I’ll try it both with Sun’s JDK and with Kaffe:

$ java Heron
Single precision:
Double precision:
$ kaffe Heron
Single precision:
Double precision:
0.0
972730.0557076167
0.0
972730.05570761673

If in doubt, use double ! To ensure consistency of very large magnitude double computations on different Java implementations, Java provides the keyword strictfp , which can apply to classes, interfaces, or methods within a class. * If a computation is Strict-FP, then it must always, for example, return the value INFINITY if a calculation would overflow the value of Double.MAX_VALUE (or underflow the value Double.MIN_VALUE ). Non-Strict- FP calculations—the default—are allowed to perform calculations on a greater range and can return a valid final result that is in range even if the interim product was out of range. This is pretty esoteric and affects only computations that approach the bounds of what fits into a double.

Java Taking a Fraction of an Integer Without Using Floating Point

Java Taking a Fraction of an Integer Without
Using Floating Point

Problem

You want to multiply an integer by a fraction without converting the fraction to a
floating-point number.

Solution

Multiply the integer by the numerator and divide by the denominator.
This technique should be used only when efficiency is more important than clarity,
as it tends to detract from the readability—and therefore the maintainability—of
your code.

Explained

Since integers and floating-point numbers are stored differently, it may sometimes be
desirable and feasible, for efficiency purposes, to multiply an integer by a fractional
value without converting the values to floating point and back, and without requiring a “cast”:

/** Compute the value of 2/3 of 5 */
public class FractMult {
public static void main(String u[]) {
double d1 = 0.666 * 5;
// fast but obscure and inaccurate: convert
System.out.println(d1); // 2/3 to 0.666 in programmer's head
double d2 = 2/3 * 5;
// wrong answer - 2/3 == 0, 0*5 = 0
System.out.println(d2);
double d3 = 2d/3d * 5;
System.out.println(d3);
double d4 = (2*5)/3d;
System.out.println(d4);
int i5 = 2*5/3;
System.out.println(i5);
// "normal"
// one step done as integers, almost same answer
// fast, approximate integer answer
}
}

Running it looks like this:
$ java FractMult
3.33
0.0
3.333333333333333
3.3333333333333335
3
$

Java Converting Numbers to Objects and Vice Versa

Java Converting Numbers to Objects
and Vice Versa

Problem

You need to convert numbers to objects and objects to numbers.

Solution

Use the Object Wrapper classes listed in Table at the beginning.

Explained

Often you have a primitive number and you need to pass it into a method where an
Object is required. This frequently happens when using the Collection classes and earlier.

To convert between an int and an Integer object, or vice versa, you can use the
following:

// IntObject.java
// int to Integer
Integer i1 = new Integer(42);
System.out.println(i1.toString( )); // or just i1
// Integer to int
int i2 = i1.intValue( );
System.out.println(i2);

Java Storing a Larger Number in a Smaller Number

Java Storing a Larger Number
in a Smaller Number

Problem

You have a number of a larger type and you want to store it in a variable of a smaller
type.

Solution

Cast the number to the smaller type. (A cast is a type listed in parentheses before a
value that causes the value to be treated as though it were of the listed type.)
For example, to cast a long to an int , you need a cast. To cast a double to a float ,
you also need a cast.

Explained

This causes newcomers some grief, as the default type for a number with a decimal
point is double , not float . So code like:

float f = 3.0;

won’t even compile! It’s as if you had written:

double tmp = 3.0;
float f = tmp;

You can fix it by making f a double , by making the 3.0 a float , by putting in a cast, or by assigning an integer value of 3:

double f = 3.0;
float f = 3.0f;
float f = 3f;
float f = (float)3.0;
float f = 3;

The same applies when storing an int into a short , char , or byte :

// CastNeeded.java
public static void main(String argv[]) {
int i;
double j = 2.75;
i = j;
// EXPECT COMPILE ERROR
i = (int)j;
// with cast; i gets 2
System.out.println("i =" + i);
byte b;
b = i;
// EXPECT COMPILE ERROR
b = (byte)i;
// with cast, i gets 2
System.out.println("b =" + b);
}

The lines marked EXPECT COMPILE ERROR do not compile unless either com- mented out or changed to be correct. The lines marked “with cast” show the correct forms.

Java Program: Apache Logfile Parsing

Java Program: Apache Logfile Parsing


The Apache web server is the world’s leading web server and has been for most of
the web’s history. It is one of the world’s best-known open source projects, and one
of many fostered by the Apache Foundation. But the name Apache is a pun on the
origins of the server; its developers began with the free NCSA server and kept hack-
ing at it or “patching” it until it did what they wanted. When it was sufficiently dif-
ferent from the original, a new name was needed. Since it was now “a patchy server,”
the name Apache was chosen. One place this patchiness shows through is in the log
file format. Consider this entry:

123.45.67.89 - - [27/Oct/2000:09:27:09 -0400] "GET /java/javaResources.html HTTP/1.0"
200 10450 "-" "Mozilla/4.6 [en] (X11; U; OpenBSD 2.8 i386; Nav)"

The file format was obviously designed for human inspection but not for easy pars- ing. The problem is that different delimiters are used: square brackets for the date, quotes for the request line, and spaces sprinkled all through. Consider trying to use a StringTokenizer ; you might be able to get it working, but you’d spend a lot of time fiddling with it. However, this somewhat contorted regular expression * makes it easy to parse:

^([\d.]+) (\S+) (\S+) \[([\w:/]+\s[+\-]\d{4})\] "(.+?)" (\d{3}) (\d+) "([^"]+)"
"([^"]+)"

You may find it informative to refer back to Table 4-2 and review the full syntax used here. Note in particular the use of the non-greedy quantifier +? in \"(.+?)\" to match a quoted string; you can’t just use .+ since that would match too much (up to the quote at the end of the line). Code to extract the various fields such as IP address, request, referer URL, and browser version is shown in Example:

LogRegExp.java
import java.util.regex.*;
/**
* Parse an Apache log file with Regular Expressions
*/
public class LogRegExp implements LogExample {
public static void main(String argv[]) {
String logEntryPattern =
"^([\\d.]+) (\\S+) (\\S+) \\[([\\w:/]+\\s[+\\-]\\d{4})\\] \"(.+?)\" (\\d{3})
(\\d+) \"([^\"]+)\" \"([^\"]+)\"";
System.out.println("Using regex Pattern:");
System.out.println(logEntryPattern);
System.out.println("Input line is:");
System.out.println(logEntryLine);
Pattern p = Pattern.compile(logEntryPattern);
Matcher matcher = p.matcher(logEntryLine);
if (!matcher.matches( ) ||
NUM_FIELDS != matcher.groupCount( )) {
System.err.println("Bad log entry (or problem with regex?):");
System.err.println(logEntryLine);
return;
}
System.out.println("IP Address: " + matcher.group(1));
System.out.println("Date&Time: " + matcher.group(4));
System.out.println("Request: " + matcher.group(5));
System.out.println("Response: " + matcher.group(6));
System.out.println("Bytes Sent: " + matcher.group(7));
if (!matcher.group(8).equals("-"))
System.out.println("Referer: " + matcher.group(8));
System.out.println("Browser: " + matcher.group(9));
}
}

The implements clause is for an interface that just defines the input string; it was used in a demonstration to compare the regular expression mode with the use of a StringTokenizer . The source for both versions is in the online source for this chap- ter. Running the program against the sample input shown above gives this output:

Using regex Pattern:
^([\d.]+) (\S+) (\S+) \[([\w:/]+\s[+\-]\d{4})\] "(.+?)" (\d{3}) (\d+) "([^"]+)"
"([^"]+)"
Input line is:
123.45.67.89 - - [27/Oct/2000:09:27:09 -0400] "GET /java/javaResources.html HTTP/1.0"
200 10450 "-" "Mozilla/4.6 [en] (X11; U; OpenBSD 2.8 i386; Nav)"
IP Address: 123.45.67.89
Date&Time: 27/Oct/2000:09:27:09 -0400
Request: GET /java/javaResources.html HTTP/1.0
Response: 200
Bytes Sent: 10450
Browser: Mozilla/4.6 [en] (X11; U; OpenBSD 2.8 i386; Nav)

The program successfully parsed the entire log file format with one call to matcher. matches( ) .

Java Controlling Case in Regular Expressions

Java Controlling Case in Regular Expressions

Problem

You want to find text regardless of case.

Solution

Compile the Pattern passing in the flags argument Pattern.CASE_INSENSITIVE to
indicate that matching should be case-independent (“fold” or ignore differences in
case). If your code might run in different locales (see Chapter 15), add Pattern.
UNICODE_CASE . Without these flags, the default is normal, case-sensitive matching
behavior. This flag (and others) are passed to the Pattern.compile() method, as in:

// CaseMatch.java
Pattern reCaseInsens = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE |
Pattern.UNICODE_CASE);
reCaseInsens.matches(input);
// will match case-insensitively

This flag must be passed when you create the Pattern ; as Pattern objects are immu- table, they cannot be changed once constructed. The full source code for this example is online as CaseMatch.java.

Pattern.compile( ) Flags 

Half a dozen flags can be passed as the second argument to Pattern.compile( ) . If more than one value is needed, they can be or’d together using the | bitwise or operator. In alphabetical order, the flags are:

CANON_EQ 

Enables so-called “canonical equivalence,” that is, characters are matched by their base character, so that the character e followed by the “combining character mark” for the acute accent ( ́ ) can be matched either by the composite character é or the letter e followed by the character mark for the accent (see Recipe 4.8). 

CASE_INSENSITIVE 

Turns on case-insensitive matching (see Recipe 4.7). 

COMMENTS 

Causes whitespace and comments (from # to end-of-line) to be ignored in the pattern. 

DOTALL 

Allows dot ( . ) to match any regular character or the newline, not just newline (see Recipe 4.9). 

MULTILINE 

Specifies multiline mode (see Recipe 4.9). 

UNICODE_CASE 

Enables Unicode-aware case folding (see Recipe 4.7). 

UNIX_LINES 

Makes \n the only valid “newline” sequence for MULTILINE mode (see Recipe 4.9).