twonums
to hold them. So the following directory holds the examples:
/import/teaching/BSc/1st/ItP/twonums
Here is a program which simply reads two numbers, and gives the result of adding them together and multiplying them together:
1 import java.io.*;
2
3 class TwoNums0
4 {
5 // A program that prompts for two numbers then prints their sum and product
6
7 public static void main (String[] args) throws IOException
8 {
9 int m,n;
10 BufferedReader in = Text.open(System.in);
11 System.out.print("Enter first number: ");
12 m=Text.readInt(in);
13 System.out.print("Enter second number: ");
14 n=Text.readInt(in);
15 System.out.println("Adding the two gives: "+(m+n));
16 System.out.println("Multiplying the two gives: "+m*n);
17 }
18 }
As with the "Hello" examples, the Text input/output class is
used to help with input from the Linux window. As this is not a standard
part of Java, you will need a copy of the file Text.class in the
directory you run the program from (this is for simplicity - there are more
sophisticated ways to enable you to reuse code without having a copy in every
directory). The readInt method in Text reads an
integer, in a similar way to how the readString method read a
string. It is used in lines 12 and 14. Line 9 declares two integer variables
(Java, like C uses the word int for integer).
You might wonder why line 15 is not:
System.out.println("Adding the two gives: "+m+n);
but if you tried editing the program to make it that way and then ran it, you
would see why. The plus sign would then be treated as the sign for joining
two strings together rather than the sign for arithmetic addition. A general
rule is that if you see something of the form a+b+c
for any a, b or c
(or two or four or more terms of course), if one of them is a string, all will
be interpreted as a string and joined together. On the other hand, if they
are all numbers they will be added together. Enclosing m+n in
brackets in line 15 meant it was treated as a separate thing and evaluated
by addition before the result was turned into a string and joined to the
words "Adding the two gives: ". There is no such problem in line 15
as
m*n is evaluated arithmetically before the + is
considered (note that in almost all programming language, multiplication is
indicated by the * symbol).
An alternative way of writing this would use two new variables to hold the
sum and product (only the main method is given here):
public static void main (String[] args) throws IOException
{
int m,n,sum,product;
BufferedReader in = Text.open(System.in);
System.out.print("Enter first number: ");
m=Text.readInt(in);
System.out.print("Enter second number: ");
n=Text.readInt(in);
sum=m+n;
System.out.println("Adding the two gives: "+sum);
product=m*n;
System.out.println("Multiplying the two gives: "+product);
}
Deciding whether to put an expression in directly or to assign it to
a separate variable and then use that variable is a matter of judgement.
Code can look cluttered if too many variables are introduced and just used
once, on the other hand it can help avoid complicated expressions.
The file TwoNums1.java is given to show there is nothing
special about the Text class. It is very similar to
TwoNums0.java except it uses a different reader. In this case,
the Java program for the reader is given, in file MyReader.java.
If you copy TwoNums1.java and MyReader.java into
your directory, and enter the Linux command:
javac TwoNums1.javayou will find that since
TwoNums1 calls MyReader,
the file MyReader.java gets compiled as well so you end up with
TwoNums1.class and MyReader.class.
MyReader
does not create a separate BufferedReader unlike Text.
It is meant to be a very simplistic reader, given just for demonstration. You
will need to know a little, but not a lot, more Java to see exactly how it
works. If you try running the TwoNums0 and TwoNums1
examples, and type in letters rather than numbers at the prompts, you will
see another difference between Text and MyReader.
Text is sophisticated enough to check for this and ask you to
type again, whereas MyReader isn't designed to cope with it
and gives strange results. This illustrates an important point: a good program
ought to be able to cope in an intelligent way when the program user does
something unexpected (and typing in numbers when letters are expected is a
good example).
Here's another thing to note - try typing in some very large numbers in response to the prompts. For example, 1000000 and 2000000 (Java does not accept the breaking up of large numbers with commas, so they must be typed just like this). You will find the multiplication gives an unexpected answer. The reason for this is that numbers are stored in a fixed amount of space in Java, which means it can only cope with numbers between a certain limit. In appendix A of Barnes' book "Object-Oriented Programming in Java", it says what these limits are. The same information can be found on page 60 of Bishop's "Java Gently" textbook and on page 144 of Deitel and Deitel's "Java How to Program". As the example shows, a calculation which goes beyond those limits simply results in an erroneous number being returned without anything special happening to let it be known that something has gone wrong.
Java, like C, however, has types which take up more storage space in the
computer and hence can store larger numbers. If you replace int
on line 9 of TwoNums.java by long a type which
stores integers but allocates twice as much space for each as int
you will find you have a program which can cope with much larger numbers.
1 import java.io.*;
2
3 class TwoNums2
4 {
5 // A program that prompts for two numbers then prints the difference between
6 // the two squares.
7
8 public static void main (String[] args) throws IOException
9 {
10 int m,n,d;
11 BufferedReader in = Text.open(System.in);
12 System.out.print("Enter first number: ");
13 m=Text.readInt(in);
14 System.out.print("Enter second number: ");
15 n=Text.readInt(in);
16 d=m*m-n*n;
17 System.out.println("The difference between the two squares is: "+d);
18 }
19 }
If the two numbers are m and n, the value calculated is
m2-n2.
The only line that's different from what we've seen before is line 16 where
the actual calculation is done. The effect of line 16 is to do the arithmetic
calculation represented by m*m-n*n substituting m
and n by the values those variables contain, then put the
result in the variable d. This may seem obvious, but it requires
a little thought to see a possible flaw. Suppose m stores 5 and
n stores 3. Then m*m-n*n evaluates to
5*5-3*3
which is surely 25-9 which is 16. That is correct.
But suppose it is typed into a calculator:
PRESS 5 PRESS MULTIPLY PRESS 5 PRESS SUBTRACT PRESS 3 PRESS MULTIPLY PRESS 3 PRESS EQUALSThe result is 66.
The reason for the difference is the order in which the arithmetic operations
are done. A calculator does them in left-to-right order, so it's really
evaluating ((5*5)-3)*3. In other words, it first multiplies
the 5 by 5, giving 25, then subtracts the 3 giving 22, then multiplies by 3
giving 66. Another way of thinking of it is as a series of rewrite operations:
d=m*m-n*nrewrites (by substituting the variable values):
d=5*5-3*3then by performing the underlined arithmetic:
d=25-3*3then by performing the next underlined arithmetic:
d=22*3However, Java, like most programming languages, tackled the arithmetic in a different way. Rather than doing the arithmetic operations in strict left-to-right order, it follows the rule that multiplications must always be done before additions, so the rewrites work:
d=m*m-n*nrewrites (by substituting the variable values):
d=5*5-3*3then by performing the underlined arithmetic:
d=25-3*3then by performing the next underlined arithmetic:
d=22-9that is, it treats the expression as if it were
(m*m)-(n*n).
The general rule is that expressions in brackets are evaluated first,
then multiplications and divisions, then additions and subtractions.
Or, as Computer Scientists put it, multiplication has a higher precedence
than addition. In the case of operators with equal precedence, Java evaluates
them in a left-to-right order, so 9-3-1 is (9-3)-1
i.e. 5, rather than 9-(3-1) i.e. 7. Page 713 of the Weiss book
has a table giving the complete precedence order of Java operators.
TwoNums3.java has exactly
the same result as the previous one, but illustrates a new concept, the idea
of a function:
1 class TwoNums3
2 {
3 // A program that prompts for two numbers then prints the difference between
4 // the two squares. Uses a separate function to find it.
5
6 public static void main (String[] args) throws IOException
7 {
8 int m,n,d;
9 BufferedReader in = Text.open(System.in);
10
11 System.out.print("Enter first number: ");
12 m=Text.readInt(in);
13 System.out.print("Enter second number: ");
14 n=Text.readInt(in);
15 d=diffTwoSquares(m,n);
16 System.out.println("The difference between the two squares is: "+d);
17 }
18
19 public static int diffTwoSquares(int p,int q)
20 {
21 int r;
22 r=p*p-q*q;
23 return r;
24 }
25
26 }
What has happened here is that the formula for calculating the difference
between the squares of two numbers has been given a name
(diffTwoSquares)
and made a separate part of the program, on lines 19-24. In languages like
C, this would be termed a function, but as Java is object-oriented it is
termed a method. However, a method which is static, indicated
by the word static as on line 19, behaves just like a C or Pascal
function. We shall explain in more detail the distinction between a function
and a standard method elsewhere.
So the class TwoNums3 has two static methods, main and
diffTwoSquares. Another name for a static method is a class
method. Note we are keeping to the convention generally
observed in Java that names made up of several words have the word
divisions indicated by starting the new words with capital letters. Java names
can't include spaces, but they can include the underscore character, so we
could have used diff_two_squares although Java's built-in library
avoids that convention. The method main is run when the program
is started from Linux, but it may call other methods which may in turn call
further methods, and so on. Line 15 is where main calls
diffTwoSquares.
A static method works exactly like main except that it takes
arguments and produces a return value. Sometimes the arguments
are described as the "input" to a function and the return value as its
"output", but it's very important to distinguish between this usage of the
terms "input" and "output" and the usage which refers to reading or
writing from the screen or a file. The function diffTwoSquares
could be said to take as input two integers and return as output the
difference between their two squares, but this does not mean that
it reads two integers or prints the difference of their squares. As you
can see, the reading is done in main on lines 11-14, and the
writing is also done in main on line 16.
diffTwoSquares only does the calculating.
The variables declared inside main (on line 8) are for use
in main only and cannot be referred to in
diffTwoSquares and the variable declared inside
diffTwoSquares (on line 21) is for use in
diffTwoSquares only and cannot be referred to in main
(there are variables called class variables which are shared across
methods in a class, but we won't look at those yet). diffTwoSquares
has two extra variables, p and q declared in its
header on line 19. When diffTwoSquares is run, p
and q are initialised to the values given to them as parameters.
In this case, line 15 in main is the call to
diffTwoSquares which causes it to be run. The arguments
m and n are used to initialise p and
q. It is as if instead of line 15 in main, we had:
p=m; q=n; r=p*p-q*q; d=r;assuming
p, q and r were declared
in main. As you can see, the function call is replaced by
assignments which match the arguments of the call to the parameters of the
function, followed by the code inside the function. The final line which follows
this shows how the return value of the function works, the value which is
returned inside diffTwoSquares, in this case r,
replaces the whole of diffTwoSquares(m,n) in what was the
original line d=diffTwoSquares(m,n).
The effect is as if diffTwoSquares were a built-in aspect of
Java rather than a part of the program we wrote ourselves. Once the method
is given, the call diffTwoSquares(x,y) for
x and y not just variables, but any
values, including complex expressions, can be used to calculate the difference
of the squares of x and y, anywhere in
the class where it is given. The word public on the header
for diffTwoSquares means that in fact it can be used outside
the class TwoNums3 as well - we shall show how that is done
shortly.
The header for diffTwoSquares also gives type information on
the method. The first int on line 19 states that the value
returned by diffTwoSquares is an integer. The second and third
int occurring before the names of its two parameters, states
that these parameters are integers as well. It is possible in Java to have
more than one method with the same name so long as the types of the parameters
differ. Which one is used depends on the types of the arguments used when the
method is called.
You may note that main has a result type (void) and
a parameter, args, with type String[]. The parameters
are used to enable command line arguments which we shall discuss
later on - in the examples you have seen so far they are not used. The type
void is a special type used to indicate that a method does not
return a value. A method which simply does some calculations but returns
no value is obviously of no use since it has no effect outside itself.
However, a method which returns no value but has some additional effect,
for example it writes something, does have a use.
1 import java.io.*;
2
3 class SquareRootPrinter
4 {
5 // A program that asks for a number and prints its square root
6
7 public static void main (String[] args) throws IOException
8 {
9 double x,xsq;
10 BufferedReader in = Text.open(System.in);
11 System.out.print("Enter a number: ");
12 x=Text.readDouble(in);
13 xsq=Math.sqrt(x);
14 System.out.println("The square root of "+x+" is "+xsq);
15 }
16 }
The square root is calculated by the call to the function sqrt
in line 13. This function comes from Java's library, in class Math
which is why the call is written Math.sqrt(x). In fact the full
name is java.lang.Math.sqrt, but you don't have to put the
java.lang in, nor do you have an import java.lang.*
line in, as you have to put an import java.io.* line in to
use methods in Java's io package, because the classes in
java.lang are treated as if already imported. The Math
class contains a variety of mathematical functions, for example trigonometry
functions. To see exactly what it contains, you could look it up in a Java
reference book, like "Java in a nutshell", or you could look at its on-line
documentation, found
here.
Note that the way a method in the system class Math is called is
no different from the way a method in some other class, for example
readDouble in Text in line 12 of the above program
is called.
The Java programming language is supplemented with an extensive library of predefined classes, known as the API (which stands for "Applications Programming Interface"). Many books and references you will see on Java are actually more on how to use the API than on the core Java language. In this course, however, we shall only consider a small part of the API that is necessary to run the examples used as the aim is to concentrate on the basics.
The method readDouble in Text is, as you might
expect from the name, one which reads a double in the way
readInt reads an integer. A double is a number
which has a fractional part, so you could type in something like
37.32 in response to the prompt. Just as integers have two types,
int and long, fractional or floating point
numbers have two types float and double, with
double taking up more computer store in order to store numbers
to more accuracy and to a greater range than float.
The great accuracy of double means the square root is
printed out to many decimal places in this program. In practice you may not
want to show it to quite so many decimal places, but if you simply print it
out by joining it to a string using + you have no choice. The
Text class provides methods which enable you to format printing
of floating point numbers. Text.writeDouble takes three
arguments - the first is the actual floating point number, the second an
integer giving the minimum number of characters used to print the number
(it will fill out with spaces to reach that figure if necessary, which is
useful to give nice layouts), the third is the number of decimal places
to which the number is printed. It returns a string which represents the
number formatted in that way. So as it takes a double and two integers
and returns a string, its header in Text (which you haven't
seen as you have only the compiled version) would be:
public static String writeDouble(double num,int align,int frac)The names used for the arguments are irrelevant, but the types are important to show how it is used. In this case, note that
writeDouble returns a vlaue but it does not
actually do the printing. The value it returns must be printed using
println. So here is a modified version of the main
method for SquareRootPrinter:
1 public static void main (String[] args) throws IOException
2 {
3 double x;
4 String xsqFormat;
5 BufferedReader in = Text.open(System.in);
6 System.out.print("Enter a number: ");
7 x=Text.readDouble(in);
8 xsqFormat=Text.writeDouble(Math.sqrt(x),5,3);
9 System.out.println("The square root of "+x+" is "+xsqFormat);
10 }
For illustration, in this case no special variable is declared just to hold
the square root, so the call to Math.sqrt occurs inside the
call to Text.readDouble, which is perfectly permissible.
We could have gone further and not had a special string variable to hold
the formatted number, in which case line 4 above is not needed, and lines 8
and 9 would be replaced by:
System.out.println("The square root of "+x+" is "+Text.writeDouble(Math.sqrt(x),5,3));
While this is still reasonable, you can begin to see how complicated
expressions may be made more understandable by breaking them up into parts
and using temporary variables.
We have already seen the use of Text to give a library of
methods useful for text input and output, and Math as Java's
own library of useful mathematical functions. We could create our own
class to hold a library of functions we find useful. The class TwoNums4
given below works similarly to TwoNums3 but expects the method
diffTwoSquares to be in a separate class MyFuncs.
For illustration, TwoNums4 extends twoNums3 by
also calling on another method, midpoint which simply finds the
midpoint between two integers.
1 import java.io.*;
2
3 class TwoNums4
4 {
5 // A program that prompts for two numbers then prints the difference between
6 // the two squares, and the midpoint. Uses methods in class MyFuncs to
7 // calculate them.
8
9 public static void main (String[] args) throws IOException
10 {
11 int m,n,d;
12 BufferedReader in = Text.open(System.in);
13 System.out.print("Enter first number: ");
14 m=Text.readInt(in);
15 System.out.print("Enter second number: ");
16 n=Text.readInt(in);
17 d=MyFuncs.diffTwoSquares(m,n);
18 System.out.println("The difference between the two squares is: "+d);
19 d=MyFuncs.midpoint(m,n);
20 System.out.println("The midpoint of the two numbers is: "+d);
21 }
22 }
The class MyFuncs exists in a separate file, called
MyFuncs.java:
1 class MyFuncs
2 {
3 // Miscellaneous functions
4
5 public static int diffTwoSquares(int p,int q)
6 {
7 return p*p-q*q;
8 }
9
10 public static int midpoint(int p,int q)
11 {
12 return (p+q)/2;
13 }
14
15 }
The advantage of this is that, just as we have reused Text
whenever we necessary, we can reuse methods from this library in any
program we write. The Java language strongly encourages reuse of programming
components rather than "reinventing the wheel" by writing completely new
programs from scratch each time.
The diffTwoSquares method on lines 5-8 of MyFuncs
looks different from the previous one because there is no separate variable
to store the calculated value. It is not necessary to have one, return
in a method can be followed by any expression. The brackets around p+q
on line 12 are needed because / has a higher precedence than
+, so p+q/2 would divide q by two then
add the result to p whereas what we want is to add p
and q and divide the result by two. Another point to note here
is that division of integers in Java (like C) always gives an integer
result. So if, say, p holds 10 and q holds 15,
(p+q)/2 won't evaluate to 12.5. Integer division always rounds
down to the nearest integer, so it will in fact give 12. This would be so
even if midpoint were written to return a double:
public static double midpoint(int p,int q)
{
return (p+q)/2;
}
(p+q)/2 with p holding 10 and q
holding 15 would evaluate to 12, and 12 would then be converted to the
double 12.0. The way to get round this is to use type
conversion. If an integer value is preceded by (double)
in Java it is converted to the equivalent double value. So, (double)(p+q)
is the double equivalent of the integer value of p+q, with
our example figures, p+q is the integer 25, while (double)(p+q)
is the double 25.0. Dividing a double by an integer gives a double, in this case
12.5.
Last modified: 13 Oct 2000