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