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

Web Development and Design | Tutorial for Java, PHP, HTML, Javascript: java-programming-examples
Showing posts with label java-programming-examples. Show all posts
Showing posts with label java-programming-examples. 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 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 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 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
$

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
$