Web Development and Design | Tutorial for Java, PHP, HTML, Javascript: Java

Web Development and Design | Tutorial for Java, PHP, HTML, Javascript: Java
Showing posts with label Java. Show all posts
Showing posts with label Java. 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 printing Date/Time in a Given Format

Java printing Date/Time in a Given Format

Problem

You want to print the date and/or time in a locale-sensitive or otherwise-specified
format.

Solution

Use java.text.DateFormat .

Explained

To print the date in the correct format for whatever locale your software lands in,
simply use the default DateFormat formatter, which is obtained by calling DateFormat.
getInstance( ) :

import java.util.*;
import java.text.*;
public class DateFormatBest {
public static void main(String[] args) {
Date today = new Date( );
DateFormat df = DateFormat.getInstance( );
System.out.println(df.format(today));
DateFormat df_fr =
DateFormat.getDateInstance(DateFormat.FULL, Locale.FRENCH);
System.out.println(df_fr.format(today));
}
}

When I run this, it prints:

3/3/04 12:17 PM
mercredi 3 mars 2004

You can ask for a default date and time formatter ( df in the example), or a TimeFormatter or DateFormatter that extracts just the time or date portion of the Date object ( df_fr in the example). You can also request a nondefault Locale ( df_fr in the example). Five codes—FULL, LONG, MEDIUM, SHORT and DEFAULT—can be passed to describe how verbose a format you want. Suppose you want the date printed, but instead of the default format, you want it printed like “Sun 2004.07.18 at 04:14:09 PM PDT”. A look at the Javadoc page for SimpleDateFormat —the only nonabstract subclass of DateFormat —reveals that it has a rich language for specifying date and time formatting. Be aware that in so doing you are presuming to know the correct format in all locales; see Chapter 15 for why this may be a bad idea. To use a default format, of course, we can just use the Date object’s toString( ) method, and for a localized default format, we use DateFormat.getInstance( ) . But to have full control and get the “Sun 2004.07.18 at 04:14:09 PM PDT”, we construct an instance explicitly, like so:

new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");

E means the day of the week; yyyy , MM , and dd are obviously year, month, and day. The quoted string 'at' means the string “at”. hh:mm:ss is the time; a means A.M. or P.M., and zzz means the time zone. Some of these are more memorable than others; I find the zzz tends to put me to sleep. Here’s the code:

// DateDemo.java
Date dNow = new Date( );
/* Simple, Java 1.0 date printing */
System.out.println("It is now " + dNow.toString( ));
// Use a SimpleDateFormat to print the date our way.
SimpleDateFormat formatter
= new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
System.out.println("It is " + formatter.format(dNow));

You can use as many of the given symbols as needed. Where a format can be used either in text or numeric context, you can set it to a longer form by repetitions of the character. For codes marked Text , four or more pattern letters cause the formatter to use the long form; fewer cause it to use the short or abbreviated form if one exists. Thus, E might yield Mon, whereas EEEE would yield Monday. For those marked Number , the number of repetitions of the symbol gives the minimum number of dig- its. Shorter numbers are zero-padded to the given number of digits. The year is han- dled specially: yy yields an ambiguous * two-digit year (98, 99, 00, 01...), whereas yyyy yields a valid year (2001). For those marked Text and Number , three or more symbols causes the formatter to use text, while one or two make it use a number: MM might yield 01, while MMM would yield January.

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: Number Palindromes

Java Program: Number Palindromes


My wife, Betty, recently reminded me of a theorem that I must have studied in high
school but whose name I have long since forgotten: that any positive integer number
can be used to generate a palindrome by adding to it the number comprised of its
digits in reverse order. Palindromes are sequences that read the same in either direc-
tion, such as the name “Anna” or the phrase “Madam, I’m Adam” (ignoring spaces
and punctuation). 

We normally think of palindromes as composed of text, but the
concept can be applied to numbers: 13531 is a palindrome. Start with the number
72, for example, and add to it the number 27. The results of this addition is 99,
which is a (short) palindrome. Starting with 142, add 241, and you get 383. Some
numbers take more than one try to generate a palindrome. 1951 + 1591 yields 3542,
which is not palindromic. The second round, however, 3542 + 2453, yields 5995,
which is. The number 17,892, which my son Benjamin picked out of the air, requires
12 rounds to generate a palindrome, but it does terminate:

C:\javasrc\numbers>java Palindrome 72 142 1951 17892
Trying 72
72->99
Trying 142
142->383
Trying 1951
Trying 3542
1951->5995
Trying 17892
Trying 47763
Trying 84537
Trying 158085
Trying 738936
Trying 1378773
Trying 5157504
Trying 9215019
Trying 18320148
Trying 102422529
Trying 1027646730
Trying 1404113931
17892->2797227972
C:\javasrc\numbers>

If this sounds to you like a natural candidate for recursion, you are correct. Recur- sion involves dividing a problem into simple and identical steps, which can be imple- mented by a function that calls itself and provides a way of termination. Our basic approach, as shown in method findPalindrome , is:

long findPalindrome(long num) {
if (isPalindrome(num))
return num;
return findPalindrome(num + reverseNumber(num));
}

That is, if the starting number is already a palindromic number, return it; otherwise, add it to its reverse, and try again. The version of the code shown here handles sim- ple cases directly (single digits are always palindromic, for example). We won’t think about negative numbers, as these have a character at the front that loses its meaning if placed at the end, and hence are not strictly palindromic. Further, palindromic forms of certain numbers are too long to fit in Java’s 64-bit long integer. These cause underflow, which is trapped. As a result, an error message like “too big” is reported. * Having said all that, Example shows the code.

Example. Palindrome.java
/** Compute the Palindrome of a number by adding the number composed of
* its digits in reverse order, until a Palindrome occurs.
* e.g., 42->66 (42+24); 1951->5995 (1951+1591=3542; 3542+2453=5995).
*/
public class Palindrome {
public static void main(String[] argv) {
for (int i=0; i<argv.length; i++)
try {
long l = Long.parseLong(argv[i]);
if (l < 0) {
System.err.println(argv[i] + " -> TOO SMALL");
continue;
}
System.out.println(argv[i] + "->" + findPalindrome(l));
} catch (NumberFormatException e) {
System.err.println(argv[i] + "-> INVALID");
} catch (IllegalStateException e) {
System.err.println(argv[i] + "-> TOO BIG(went negative)");
}
}
/** find a palindromic number given a starting point, by
* calling ourself until we get a number that is palindromic.
*/
static long findPalindrome(long num) {
if (num < 0)
throw new IllegalStateException("went negative");
if (isPalindrome(num))
return num;
System.out.println("Trying " + num);
return findPalindrome(num + reverseNumber(num));
}
/** The number of digits in Long.MAX_VALUE */
protected static final int MAX_DIGITS = 19;
// digits array is shared by isPalindrome and reverseNumber,
// which cannot both be running at the same time.
/* Statically allocated array to avoid new-ing each time. */
static long[] digits = new long[MAX_DIGITS];
/** Check if a number is palindromic. */
static boolean isPalindrome(long num) {
if (num >= 0 && num <= 9)
return true;
int nDigits = 0;
while (num > 0) {
digits[nDigits++] = num % 10;
num /= 10;
}
for (int i=0; i<nDigits/2; i++)
if (digits[i] != digits[nDigits - i - 1])
return false;
return true;
}
static long reverseNumber(long num) {
int nDigits = 0;
while (num > 0) {
digits[nDigits++] = num % 10;
num /= 10;
}
long ret = 0;
for (int i=0; i<nDigits; i++) {
ret *= 10;
ret += digits[i];
}
return ret;
}
}

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 Using Complex Numbers

Java Using Complex Numbers

Problem

You need to manipulate complex numbers, as is common in mathematical, scien-
tific, or engineering applications.

Solution

Java does not provide any explicit support for dealing with complex numbers. You
could keep track of the real and imaginary parts and do the computations yourself,
but that is not a very well-structured solution.

A better solution, of course, is to use a class that implements complex numbers. I
provide just such a class. First, an example of using it:

// ComplexDemo.java
Complex c = new Complex(3, 5);
Complex d = new Complex(2, -2);
System.out.println(c + ".getReal( )= " + c.getreal());
System.out.println(c + " + " + d + " = " + c.add(d));
System.out.println(c + " + " + d + " = " + Complex.add(c, d));
System.out.println(c + " * " + d + " = " + c.multiply(d));

Example is the complete source for the Complex class and shouldn’t require much explanation. To keep the API general, I provide—for each of add, subtract, and mul- tiply—both a static method that works on two complex objects and a nonstatic method that applies the operation to the given object and one other object.

/** A class to represent Complex Numbers. A Complex object is
* immutable once created; the add, subtract and multiply routines
* return newly created Complex objects containing the results.
*
*/
public class Complex {
/** The real part */
private double r;
/** The imaginary part */
private double i;
/** Construct a Complex */
Complex(double rr, double ii) {
r = rr;
i = ii;
}
/** Display the current Complex as a String, for use in
* println( ) and elsewhere.
*/
public String toString( ) {
StringBuffer sb = new StringBuffer( ).append(r);
if (i>0)
sb.append('+');
// else append(i) appends - sign
return sb.append(i).append('i').toString( );
}

/** Return just the Real part */
public double getReal( ) {
return r;
}
/** Return just the Real part */
public double getImaginary( ) {
return i;
}
/** Return the magnitude of a complex number */
public double magnitude( ) {
return Math.sqrt(r*r + i*i);
}
/** Add another Complex to this one */
public Complex add(Complex other) {
return add(this, other);
}
/** Add two Complexes */
public static Complex add(Complex c1, Complex c2) {
return new Complex(c1.r+c2.r, c1.i+c2.i);
}

/** Subtract another Complex from this one */
public Complex subtract(Complex other) {
return subtract(this, other);
}
/** Subtract two Complexes */
public static Complex subtract(Complex c1, Complex c2) {
return new Complex(c1.r-c2.r, c1.i-c2.i);
}
/** Multiply this Complex times another one */
public Complex multiply(Complex other) {
return multiply(this, other);
}
/** Multiply two Complexes */
public static Complex multiply(Complex c1, Complex c2) {
return new Complex(c1.r*c2.r - c1.i*c2.i, c1.r*c2.i + c1.i*c2.r);
}
/** Divide c1 by c2.
* @author Gisbert Selke.
*/
public static Complex divide(Complex c1, Complex c2) {
return new Complex(
(c1.r*c2.r+c1.i*c2.i)/(c2.r*c2.r+c2.i*c2.i),
(c1.i*c2.r-c1.r*c2.i)/(c2.r*c2.r+c2.i*c2.i));
}
}

Java Multiplying Matrices

Java Multiplying Matrices

Problem

You need to multiply a pair of two-dimensional arrays, as is common in mathematical and engineering applications.

Solution

Use the following code as a model.

Explained

It is straightforward to multiply an array of a numeric type. The code in Example
implements matrix multiplication. Example Matrix.java

/**
* Multiply two matrices.
* Only defined for int:
* for long, float, and double.
*/
public class Matrix {
/* Matrix-multiply two arrays together.
* The arrays MUST be rectangular.
* @author Tom Christiansen & Nathan Torkington, Perl Cookbook version.
*/
public static int[][] multiply(int[][] m1, int[][] m2) {
int m1rows = m1.length;
int m1cols = m1[0].length;
int m2rows = m2.length;
int m2cols = m2[0].length;
if (m1cols != m2rows)
throw new IllegalArgumentException(
"matrices don't match: " + m1cols + " != " + m2rows);
int[][] result = new int[m1rows][m2cols];
// multiply
for (int i=0; i<m1rows; i++)
for (int j=0; j<m2cols; j++)
for (int k=0; k<m1cols; k++)
result[i][j] += m1[i][k] * m2[k][j];
return result;
}

public static void mprint(int[][] a) {
int rows = a.length;
int cols = a[0].length;
System.out.println("array["+rows+"]["+cols+"] = {");
for (int i=0; i<rows; i++) {
System.out.print("{");
for (int j=0; j<cols; j++)
System.out.print(" " + a[i][j] + ",");
System.out.println("},");
}
System.out.println(":;");
}
}

Here is a program that uses the Matrix class to multiply two arrays of int s:

// MatrixUse.java
int x[][] = {
{ 3, 2, 3 },
{ 5, 9, 8 },
};
int y[][] = {
{ 4, 7 },
{ 9, 3 },
{ 8, 1 },
};
int z[][] = Matrix.multiply(x, y);
Matrix.mprint(x);
Matrix.mprint(y);
Matrix.mprint(z);

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 Generating Random Numbers

Java Generating Random Numbers


Problem

You need to generate random numbers in a hurry.

Solution

Use java.lang.Math.random( ) to generate random numbers. There is no claim that
the random values it returns are very good random numbers, however. This code
exercises the random( ) method:

// Random1.java
// java.lang.Math.random( ) is static, don't need to construct Math
System.out.println("A random from java.lang.Math is " + Math.random( ));

Note that this method only generates double values. If you need integers, you need to scale and round:

/** Generate random ints by asking Random( ) for
* a series of random integers from 1 to 10, inclusive.
*
* @author Ian Darwin, http://www.darwinsys.com/
* @version $Id: ch05,v 1.5 2004/05/04 20:11:35 ian Exp $
*/
public class RandomInt {
public static void main(String[] a) {
Random r = new Random( );
for (int i=0; i<1000; i++)
// nextInt(10) goes from 0-9; add 1 for 1-10;
System.out.println(1+Math.round(r.nextInt(10)));
}
}

To see if it was really working well, I used the Unix tools sort and uniq, which, together, give a count of how many times each value was chosen. For 1,000 integers, each of 10 values should be chosen about 100 times:

C:> java RandomInt | sort -n | uniq -c
110 1
106 2
98 3
109 4
108 5
99 6
94 7
91 8
94 9
91 10
C:>

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 Operating on a Series of Integers

Java Operating on a Series of Integers

Problem

You need to work on a range of integers.

Solution

For a contiguous set, use a for loop.

Explained

To process a contiguous set of integers, Java provides a for loop. * Loop control for
the for loop is in three parts: initialize, test, and change. If the test part is initially
false, the loop will never be executed, not even once.

For discontinuous ranges of numbers, use a java.util.BitSet .

The following program demonstrates all of these techniques:

import java.util.BitSet;
/** Operations on series of numbers */
public class NumSeries {
public static void main(String[] args) {

// When you want an ordinal list of numbers, use a for loop
// starting at 1.
for (int i = 1; i <= months.length; i++)
System.out.println("Month # " + i);
// When you want a set of array indexes, use a for loop
// starting at 0.
for (int i = 0; i < months.length; i++)
System.out.println("Month " + months[i]);
// For a discontiguous set of integers, try a BitSet
// Create a BitSet and turn on a couple of bits.
BitSet b = new BitSet( );
b.set(0);
// January
b.set(3);
// April
// Presumably this would be somewhere else in the code.
for (int i = 0; i<months.length; i++) {
if (b.get(i))
System.out.println("Month " + months[i] + " requested");
}
}
/** The names of the months. See Dates/Times chapter for a better way */
protected static String months[] = {
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"
};
}

Java Converting Between Binary, Octal, Decimal, and Hexadecimal

Java Converting Between Binary, Octal, Decimal,
and Hexadecimal

Problem

You want to display an integer as a series of bits—for example, when interacting
with certain hardware devices. You want to convert a binary number or a hexadecimal value into an integer.

Solution

The class java.lang.Integer provides the solutions. Use toBinaryString( ) to con-
vert an integer to binary. Use valueOf( ) to convert a binary string to an integer:

// BinaryDigits.java
String bin = "101010";
System.out.println(bin + " as an integer is " + Integer.valueOf(bin, 2));
int i = 42;
System.out.println(i + " as binary digits (bits) is " +
Integer.toBinaryString(i));

This program prints the binary as an integer, and an integer as binary:

$ java BinaryDigits
101010 as an integer is 42
42 as binary digits (bits) is 101010
$



Explained

Integer.valueOf( ) is more general than binary formatting. It also converts a string number from any radix to int , just by changing the second argument. Octal is base 8, decimal is 10, hexadecimal 16. Going the other way, the Integer class includes toBinaryString( ) , toOctalString( ) , and toHexString( ) . The String class itself includes a series of static methods, valueOf(int) , valueOf(double) , and so on, that also provide default formatting. That is, they return the given numeric value formatted as a string.

Java Formatting Numbers

Java Formatting Numbers


Problem

You need to format numbers.

Solution

Use a NumberFormat subclass.

Java has not traditionally provided a C-style printf /scanf functions because they tend
to mix together formatting and input/output in a very inflexible way. Programs using
printf /scanf can be very hard to internationalize, for example.

Java has an entire package, java.text , full of formatting routines as general and flexi-
ble as anything you might imagine. As with printf, it has an involved formatting lan-
guage, described in the Javadoc page. Consider the presentation of long numbers. In
North America, the number one thousand twenty-four and a quarter is written
1,024.25, in most of Europe it is 1 024,25, and in some other part of the world it
might be written 1.024,25. Not to mention how currencies and percentages are for-
matted! Trying to keep track of this yourself would drive the average small software
shop around the bend rather quickly.

Fortunately, the java.text package includes a Locale class, and, furthermore, the
Java runtime automatically sets a default Locale object based on the user’s environ-
ment; e.g., on the Macintosh and Windows, the user’s preferences; on Unix, the
user’s environment variables. (To provide a nondefault locale, see Recipe 15.8.) To
provide formatters customized for numbers, currencies, and percentages, the
NumberFormat class has static factory methods that normally return a DecimalFormat
with the correct pattern already instantiated. A DecimalFormat object appropriate to
the user’s locale can be obtained from the factory method NumberFormat.
getInstance( ) and manipulated using set methods. Surprisingly, the method
setMinimumIntegerDigits( ) turns out to be the easy way to generate a number for-
mat with leading zeros. Here is an example:

import java.text.*;
import java.util.*;
/*
* Format a number our way and the default way.
*/
public class NumFormat2 {
/** A number to format */
public static final double data[] = {
0, 1, 22d/7, 100.2345678
};
/** The main (and only) method in this class. */
public static void main(String av[]) {
// Get a format instance
NumberFormat form = NumberFormat.getInstance( );
// Set it to look like 999.99[99]
form.setMinimumIntegerDigits(3);
form.setMinimumFractionDigits(2);
form.setMaximumFractionDigits(4);
// Now print using it.
for (int i=0; i<data.length; i++)
System.out.println(data[i] + "\tformats as " +
form.format(data[i]));
}
}

This prints the contents of the array using the NumberFormat instance form :

$ java NumFormat2
0.0
formats as 000.00
1.0
formats as 001.00
3.142857142857143
formats as 003.1429
100.2345678
formats as 100.2346
$

You can also construct a DecimalFormat with a particular pattern or change the pat- tern dynamically using applyPattern( ) . Some of the more common pattern charac- ters are shown in Table
Table DecimalFormat pattern characters

Character                                                                            Meaning

#                                                                    Numeric digit (leading zeros suppressed)

0                                                                      Numeric digit (leading zeros provided)

.                                                                  Locale-specific decimal separator (decimal point)

,                                                              Locale-specific grouping separator (comma in English)

-                                                              Locale-specific negative indicator (minus sign)

%                                                             Shows the value as a percentage

;                                    Separates two formats: the first for positive and the second for negative values

'                                             Escapes one of the above characters so it appears
                                                                   Anything else Appears as itself


The NumFormatTest program uses one DecimalFormat to print a number with only two
decimal places and a second to format the number according to the default locale:

// NumFormatTest.java
/** A number to format */
public static final double intlNumber = 1024.25;
/** Another number to format */
public static final double ourNumber = 100.2345678;
NumberFormat defForm = NumberFormat.getInstance( );
NumberFormat ourForm = new DecimalFormat("##0.##");
// toPattern( ) shows the combination of #0., etc
// that this particular local uses to format with
System.out.println("defForm's pattern is " +
((DecimalFormat)defForm).toPattern( ));
System.out.println(intlNumber + " formats as " +
defForm.format(intlNumber));
System.out.println(ourNumber + " formats as " +
ourForm.format(ourNumber));
System.out.println(ourNumber + " formats as " +
defForm.format(ourNumber) + " using the default format");

This program prints the given pattern and then formats the same number using several formats:

$ java NumFormatTest
defForm's pattern is #,##0.###
1024.25 formats as 1,024.25
100.2345678 formats as 100.23
100.2345678 formats as 100.235 using the default format
$