Skip to content

2. The basis of the Java Language

2.1. Introduction

We will first treat Java as a traditional programming language. We will cover objects later.

In a program, there are two things

  • data
  • the instructions that manipulate them

We generally strive to separate data from instructions:

Image

2.2. Java Data

Java uses the following data types:

  • integers
  • floating-point numbers
  • characters and strings
  • Booleans
  • objects

2.2.1. Predefined data types

Type
Encoding
Range
char
2 bytes
Unicode character
int
4 bytes
[-231, 231 -1]
long
8 bytes
[-263, 263 -1]
byte
1 byte
[-27 , 27 -1]
short
2 bytes
[-2(15), 2(15),-1]
float
4 bytes
[3.410⁻³⁸, 3.410³⁸] in absolute value
double
8 bytes
[1.7 × 10⁻³⁰⁸, 1.7 × 10³⁰⁸] in absolute value
boolean
1 bit
true, false
String
object reference
string
Date
object reference
date
Character
object reference
char
Integer
object reference
int
Long
object reference
long
Byte
object reference
byte
Float
object reference
float
Double
object reference
double
Boolean
object reference
Boolean

2.2.2. Literal data notation

integer
145, -7, 0xFF (hexadecimal)
double
134.789, -45E-18 (-45 × 10⁻¹⁸)
float
134.789F, -45E-18F (-45 × 10⁻¹⁸)
character
'A', 'b'
string
"today"
boolean
true, false
date
new Date(13,10,1954) (day, month, year)

2.2.3. Data declaration

2.2.3.1. Role of declarations

A program manipulates data characterized by a name and a type. This data is stored in memory. When the program is compiled, the compiler assigns each piece of data a memory location characterized by an address and a size. It does this using the declarations made by the programmer.

Furthermore, these declarations allow the compiler to detect programming errors. Thus, the operation

x=x*2;

will be declared incorrect if x is a string, for example.

2.2.3.2. Declaration of Constants

The syntax for declaring a constant is as follows:

**<mark style="background-color: #ffff00">final </mark>**<mark style="background-color: #ffff00">type name=value;</mark>           //defines constant name=value

ex: final float PI=3.141592F;

Note

Why declare constants?

  • The program will be easier to read if the constant is given a meaningful name:
ex: *final float VAT\_rate=0.186F*;
  • Modifying the program will be easier if the "constant" needs to be changed. Thus, in the previous case, if the VAT rate changes to 33%, the only modification needed will be to change the statement defining its value:
*final float tax\_rate=0.33F*;

If we had used 0.186 explicitly in the program, we would then have to modify numerous statements.

2.2.3.3. Variable Declaration

A variable is identified by a name and refers to a data type. A Java variable name consists of n characters, the first of which must be a letter, and the rest can be letters or numbers. Java distinguishes between uppercase and lowercase letters. Thus, the variables FIN and fin are different.

Variables can be initialized when they are declared. The syntax for declaring one or more variables is:

type_identifier variable1,variable2,...,variablen;

where type_identifier is a predefined type or an object type defined by the programmer.

2.2.4. Conversions between numbers and character strings

number -> string
"" + number
string -> int
Integer.parseInt(string)
string -> long
Long.parseLong(string)
string -> double
Double.valueOf(string).doubleValue()
string -> float
Float.valueOf(string).floatValue()

Here is a program that demonstrates the main techniques for converting between numbers and strings. Converting a string to a number may fail if the string does not represent a valid number. This results in a fatal error, known as an exception in Java. This error can be handled using the following try/catch block:

try{
    call to the function likely to generate the exception
} catch (Exception e){
    handle the exception e
}
next statement

If the function does not throw an exception, the program proceeds to the next statement; otherwise, it enters the body of the catch clause and then proceeds to the next statement. We will return to exception handling later.


import java.io.*;

public class conv1{

  public static void main(String arg[]){
    String S;
    final int i = 10;
    final long l = 100000;
    final float f = (float) 45.78;
    double d = -14.98;

    // number --> string
    S = "" + i;
    display(S);
    S = "" + l;
    display(S);
    S = "" + f;
    display(S);
    S = " " + d;
    display(S);

    //boolean --> string
    final boolean b = false;
    S = "" + new Boolean(b);
    display(S);

    // string --> int
    int i1;
    i1 = Integer.parseInt("10");
    display(""+i1);
    try{
      i1 = Integer.parseInt("10.67");
      display("" + i1);
    } catch (Exception e){
      display("Error " + e);
    }

    // string --> long
    long l1;
    l1 = Long.parseLong("100");
    display(""+l1);
    try{
      l1 = Long.parseLong("10.675");
      display("" + l1);
    } catch (Exception e){
      display("Error " + e);
    }
    
    // string --> double
    double d1;
    d1 = Double.valueOf("100.87").doubleValue();
    display("" + d1);
    try{
      d1 = Double.valueOf("abcd").doubleValue();
      display("" + d1);
    } catch (Exception e){
      display("Error " + e);
    }

    // string --> float
    float f1;
    f1 = Float.valueOf("100.87").floatValue();
    display("" + f1);
    try{
      d1 = Float.valueOf("abcd").floatValue();
      display("" + f1);
    } catch (Exception e){
      display("Error " + e);
    }

}// end of main

  public static void display(String S){
    System.out.println("S=" + S);
  }
}// end class

The results are as follows:

S=10
S=100000
S=45.78
S=-14.98
S=false
S=10
S=Error java.lang.NumberFormatException: 10.67
S=100
S=Error java.lang.NumberFormatException: 10.675
S=100.87
S=Error java.lang.NumberFormatException: abcd
S=100.87
S=Error java.lang.NumberFormatException: abcd

2.2.5. Data Arrays

A Java array is an object that allows data of the same type to be grouped under a single identifier. It is declared as follows:

Type Array[] = new Type[n] or Type[] Array = new Type[n]

Both syntaxes are valid. n is the number of elements the array can hold. The syntax Array[i] refers to the element at index i, where i is in the range [0,n-1]. Any reference to the element Array[i] where i is not in the range [0,n-1] will cause an exception.

A two-dimensional array can be declared as follows:

Type Array[][] = new Type[n][p] or Type[][] Array = new Type[n][p]

The syntax Array[i] refers to data element i of Array where i belongs to the interval [0,n-1]. Array[i] is itself an array: Array[i][j] refers to the jth element of Array[i], where j belongs to the interval [0,p-1]. Any reference to an element of Array with incorrect indices generates a fatal error.

Here is an example:


public class test1{

  public static void main(String arg[]){
    float[][] rate = new float[2][2];
    rate[1][0] = 0.24F;
    rate[1][1] = 0.33F;
    System.out.println(rate[1].length);
    System.out.println(rate[1][1]);
  }
}

and the results of the execution:

2
0.33

An array is an object with a length attribute: this is the size of the array.

2.3. Basic Java Commands

We distinguish

  • the basic instructions executed by the computer.
  • instructions that control the flow of the program.

Basic instructions become clear when considering the structure of a microcomputer and its peripherals.

Image

  1. Reading information from the keyboard

  2. Processing information

  3. Writing information to the screen

  4. Reading information from a disk file

  5. Writing information to a disk file

2.3.1. Writing to the screen

The syntax for the screen output statement is as follows:

System.out.println(expression) or System.err.println(expression)

where expression is any data type that can be converted to a string to be displayed on the screen. In the previous example, we saw two print statements:

System.out.println(rate[1].length);
System.out.println(taux[1][1]);

System.out writes to a text file, which by default is the screen. The same applies to System.err. These files are assigned numbers (or descriptors) 1 and 2, respectively. The keyboard input stream (System.in) is also treated as a text file, with descriptor 0. Both DOS and Unix support command piping:

    command1 | command2

Everything that command1 writes to System.out is piped (redirected) to the System.in input of command2. In other words, command2 reads from System.in the data produced by command2 via System.out, which is therefore no longer displayed on the screen. This system is widely used in Unix. In this piping, the System.err stream is not redirected: it writes to the screen. This is why it is used to write error messages (hence its name err): we can be sure that when commands are piped, error messages will continue to appear on the screen. We should therefore get into the habit of writing error messages to the screen using the System.err stream rather than the System.out stream.

2.3.2. Reading data typed on the keyboard

The data stream from the keyboard is represented by the System.in object of type InputStream. This type of object allows data to be read character by character. It is up to the programmer to then extract the relevant information from this character stream. The InputStream type does not allow a line of text to be read all at once. The BufferedReader type allows this using the readLine method.

To read lines of text entered via the keyboard, we create a new input stream of type BufferedReader from the System.in* input stream of type InputStream*:

BufferedReader IN = new BufferedReader(new InputStreamReader(System.in));

We will not explain the details of this statement here, as it involves the concept of object construction. We will use it as is.

Creating a stream can fail: a fatal error, called an exception in Java, is then generated. Whenever a method is likely to generate an exception, the Java compiler requires that it be handled by the programmer. Therefore, to create the previous input stream, we must actually write:


BufferedReader IN=null;
try{
IN = new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e){
        System.err.println("Error " + e);
        System.exit(1);
}

Again, we won’t go into detail about exception handling here. Once the previous IN stream has been created, we can read a line of text using the statement:

    String line;
    line = IN.readLine();

The line typed on the keyboard is stored in the variable line and can then be used by the program.

2.3.3. Input/Output Example

Here is a program illustrating keyboard/screen input/output operations:


import java.io.*;        // required for using I/O streams

public class io1{
  
  
  public static void main (String[] arg){
    
    // write to the System.out stream
    Object obj = new Object();
    System.out.println("" + obj);
    System.out.println(obj.getClass().getName());
    
    // Write to the System.err stream
    int i = 10;
    System.err.println("i=" + i);
    
    // reading a line entered from the keyboard
    String line;
    BufferedReader IN = null;
    try{
      IN = new BufferedReader(new InputStreamReader(System.in));
    } catch (Exception e) {
      display(e);
      System.exit(1);
    }
    System.out.print("Enter a line: ");
    try{
      line = IN.readLine();
      System.out.println("line=" + line);
    } catch (Exception e){
      display(e);
      System.exit(2);
    }
  }//end of main

  public static void display(Exception e){
    System.err.println("Error: " + e);
  }

}//end class

and the results of the execution:

C:\Serge\java\bases\iostream>java io1
java.lang.Object@1ee78b
java.lang.Object
i=10
Type a line: I am here
line=I'm here

The instructions

Object obj = new Object();
System.out.println("" + obj);
System.out.println(obj.getClass().getName());

are intended to show that any object can be displayed. We will not attempt here to explain the meaning of what is displayed. We also have the display of an object's value in the block:

try{
      IN = new BufferedReader(new InputStreamReader(System.in));
    } catch (Exception e){
      display(e);
      System.exit(1);
    }

The variable e is an Exception object that is displayed here using the display(e) call. We encountered this display of an exception’s value in the conversion program seen earlier, though we did not discuss it at the time.

2.3.4. Assigning the value of an expression to a variable

Here we are interested in the operation variable=expression;

The expression can be of the following types: arithmetic, relational, Boolean, string

2.3.4.1. Interpretation of the assignment operation

The operation variable=expression; is itself an expression whose evaluation proceeds as follows:

  • The right-hand side of the assignment is evaluated: the result is a value V.
  • The value V is assigned to the variable
  • The value V is also the value of the assignment, now viewed as an expression.

This is why the expression V1=V2=expression is valid. Due to precedence, the rightmost = operator will be evaluated. We therefore have V1=(V2=expression). The expression V2=expression is evaluated and has the value V. Evaluating this expression caused V to be assigned to V2. The next = operator is then evaluated as V1=V. The value of this expression is still V. Its evaluation causes V to be assigned to V1. Thus, the operation V1=V2=expression is an expression whose evaluation

1: causes the value of expression to be assigned to the variables V1 and V2

2: returns the value of expression as the result.

We can generalize this to an expression of the form: V1=V2=....=Vn=expression

2.3.4.2. Arithmetic expression

The operators for arithmetic expressions are as follows:

+: addition

  • : subtraction

*: multiplication

/ : division: the result is the exact quotient if at least one of the operands is real. If both operands are integers, the result is the integer quotient. Thus, 5/2 -> 2 and 5.0/2 -> 2.5.

% : division : the result is the remainder regardless of the nature of the operands, with the quotient being an integer. This is therefore the modulo operation.

There are various mathematical functions:

double sqrt(double x)
square root
double cos(double x)
Cosine
double sin(double x)
Sine
double tan(double x)
Tangent
double pow(double x, double y)
x to the power of y (x > 0)
double exp(double x)
Exponential
double log(double x)
Natural logarithm
double abs(double x)
absolute value

etc...

All these functions are defined in a Java class called Math. When using them, you must prefix them with the name of the class in which they are defined. Thus, you would write:

double x, y = 4;
x = Math.sqrt(y);

The definition of the Math class is as follows:


public final      class java.lang.Math
    extends java.lang.Object  (I-§1.12)
{
        // Fields
    public final static double E;    §1.10.1
    public final static double pi;    §1.10.2

        // Methods
    public static double abs(double a);    §1.10.3
    public static float abs(float a);    §1.10.4
    public static int abs(int a);    §1.10.5
    public static long abs(long a);    §1.10.6
    public static double acos(double a);    §1.10.7
    public static double asin(double a);    §1.10.8
    public static double atan(double a);    §1.10.9
    public static double atan2(double a, double b);    §1.10.10
    public static double ceil(double a);    §1.10.11
    public static double cos(double a);    §1.10.12
    public static double exp(double a);    §1.10.13
    public static double floor(double a);    §1.10.14
    public static double §1.10.15
        IEEEremainder(double   f1, double   f2);
    public static double log(double a);    §1.10.16
    public static double max(double a, double b);    §1.10.17
    public static float max(float a, float b);    §1.10.18
    public static int max(int a, int b);    §1.10.19
    public static long max(long a, long b);    §1.10.20
    public static double min(double a, double b);     §1.10.21
    public static float min(float a, float b);    §1.10.22
    public static int min(int a, int b);    §1.10.23
    public static long min(long a, long b);    §1.10.24
    public static double pow(double a, double b);    §1.10.25
    public static double random();    §1.10.26
    public static double rint(double a);    §1.10.27
    public static long round(double a);    §1.10.28
    public static int round(float a);    §1.10.29
    public static double sin(double a);    §1.10.30
    public static double sqrt(double a);    §1.10.31
    public static double tan(double a);    §1.10.32
}

2.3.4.3. Operators in the evaluation of arithmetic expressions

The precedence of operators when evaluating an arithmetic expression is as follows (from highest to lowest):

[functions], [ ( )], [ *, /, %], [+, -]

Operators within the same block [ ] have the same precedence.

2.3.4.4. Relational operators

The operators are as follows: <, <=, ==, !=, >, >=

Order of precedence

       &gt;, &gt;=, &lt;, &lt;=

       ==, !=

The result of a relational expression is the Boolean value false if the expression is false; otherwise, it is true.

Example:

      boolean end;
      int x;
      end = x > 4;

Comparison of two characters

Let there be two characters C1 and C2. They can be compared using the operators

&lt;, &lt;=, ==, !=, &gt;, &gt;=

In this case, their ASCII codes—which are numbers—are compared. Recall that according to the ASCII order, the following relationships hold:

space < .. < '0' < '1' < .. < '9' < .. < 'A' < 'B' < .. < 'Z' < .. < 'a' < 'b' < .. < 'z'

Comparison of two character strings

They are compared character by character. The first inequality encountered between two characters results in an inequality of the same direction for the strings.

Examples:

Consider comparing the strings "Cat" and "Dog"

This last inequality allows us to conclude that "Cat" < "Dog".

Image

Consider comparing the strings "Cat" and "Kitten". They are equal throughout until the string "Cat" is exhausted. In this case, the exhausted string is declared the "smaller" one. We therefore have the relation

&quot;Cat&quot; &lt; &quot;Kitten&quot;.

Functions for comparing two strings

We cannot use the relational operators <, <=, ==, !=, >, >= here. We must use methods from the String class:

String string1, string2;
string1 = ;
string2 = ;
int i = string1.compareTo(string2);
boolean equal = string1.equals(string2)

In the above code, the variable i will have the value:

    0: if the two strings are equal

    1: if string 1 &gt; string 2

    -1: if string 1 &lt; string 2

The variable equal will have the value true if the two strings are equal.

2.3.4.5. Boolean expressions

The operators are & (and), || (or), and ! (not). The result of a Boolean expression is a Boolean.

Order of precedence ! , &&, ||

example:

int end;
int x;
end = x > 2 && x < 4;

Relational operators have precedence over the && and || operators.

2.3.4.6. Bitwise operations

The operators

Let i and j be two integers.

i<<n
shifts i n bits to the left. The incoming bits are zeros.
i>>n
shifts i n bits to the right. If i is a signed integer (signed char, int, long), the sign bit is preserved.
i & j
Performs the logical AND of i and j bit by bit.
i | j
performs the logical OR of i and j bit by bit.
~i
complements i to 1
i^j
performs the XOR of i and j

Let

    int i=0x123F, k=0xF123;
    unsigned j = 0xF123;
operation
value
i<<4
0x23F0
i>>4
0x0123 the sign bit is preserved.
k>>4
0xFF12 the sign bit is preserved.
i&j
0x1023
i|j
0xF33F
~i
0xEDC0

2.3.4.7. Combination of operators

   a=a+b can be written as a+=b

   a=a-b can be written as a-=b

The same applies to the operators /, %, *, <<, >>, &, |, ^

Thus, a=a+2; can be written as a+=2;

2.3.4.8. Increment and decrement operators

The notation variable++ means variable=variable+1 or variable+=1

The notation variable-- means variable=variable-1 or variable-=1.

2.3.4.9. The ? operator

The expression expr_cond ? expr1:expr2 is evaluated as follows:

1: The expression expr_cond is evaluated. This is a conditional expression with a value of true or false

2: If it is true, the value of the expression is that of expr1. expr2 is not evaluated.

3: If it is false, the opposite occurs: the value of the expression is that of expr2. expr1 is not evaluated.

Example

*i = (j &gt; 4 ? j + 1 : j - 1);*

will assign to the variable i:

j+1 if j>4, j-1 otherwise

This is the same as writing if(j>4) i=j+1; else i=j-1; but it is more concise.

2.3.4.10. General operator precedence

() [] function
gd
! ~ ++ --
dg
new (type) cast operators
dg
* / %
gd
+ -
gd
<< >>
gd
< <= > >= instanceof
gd
== !=
gd
&
gd
^
gd
|
gd
&&
gd
||
gd
? :
dg
= += -= etc. .
dg

gd: indicates that, for operators of equal precedence, left-to-right precedence is observed. This means that when an expression contains operators of the same precedence, the operator furthest to the left in the expression is evaluated first. dg indicates right-to-left precedence.

2.3.4.11. Type Casting

It is possible, within an expression, to temporarily change the representation of a value. This is called type casting. The syntax for changing the type of a value in an expression is (type) value. The value then takes on the specified type. This results in a change in the value’s representation.

Example:

int i, j;
float isurj;
isurj = (float)i/j;   // parentheses take precedence over division

Here, it is necessary to cast i or j to a floating-point type; otherwise, the division will return an integer quotient rather than a floating-point value.

     *i* is a value exactly encoded in 2 bytes

     *(float) i* is the same value, approximately encoded as a floating-point number over 4 bytes

There is therefore a type conversion of the value of i. This conversion occurs only for the duration of a calculation; the variable i always retains its int type.

2.4. Program flow control statements

2.4.1. Stop

The exit method defined in the System class allows you to stop the execution of a program.

Syntax : void exit(int status)

Action  : stops the current process and returns the status value to the parent process

exit terminates the current process and returns control to the calling process. The status value can be used by the calling process. Under DOS, this status variable is returned to DOS in the system variable ERRORLEVEL, whose value can be checked in a batch file. Under Unix, the $? variable retrieves the status value if the command interpreter is the Bourne Shell (/bin/sh).

Example:

    System.exit(0);

to terminate the program with a status value of 0.

2.4.2. Simple conditional structure


 syntax:  if (condition) {actions_true_condition;} else {actions_false_condition;}

notes:

  • The condition is enclosed in parentheses.
  • Each action is terminated by a semicolon.
  • Curly braces are not followed by a semicolon.
  • Curly braces are only necessary if there is more than one action.
  • The else clause may be omitted.
  • There is no "then".

The algorithmic equivalent of this structure is the if-then-else structure:

if condition
  then true_condition_actions
  else actions_for_false_condition
end

example


    if (x > 0) { nx = nx + 1; sx = sx + x; } else dx = dx - x;

You can nest decision structures:

if(condition1)
if (condition2)
        {......}
      else         //condition2
         {......}
else         //condition1
     {.......}

The following problem sometimes arises:


public static void main(void){
      int n = 5;

   if(n > 1)
     if (n > 6)
             System.out.println(">6");
     else System.out.println("<=6");
}

In the previous example, which if statement does the else refer to? The rule is that an else always refers to the nearest *if statement: if(n&gt;6)* in this example. Let's consider another example:


public static void main(void)
{  int n=0;

   if(n>1)
     if(n>6)   System.out.println(">6");
     else;            // else branch of the if(n>6) statement: nothing to do 
   else System.out.println("<=1");    // else branch of the if(n>1) 
}

Here we wanted to put an else in the if(n>1) statement and no else in the if(n>6) statement. Because of the previous note, we are forced to put an else in the if(n>6) statement, in which there is no statement.

2.4.3. Case structure

The syntax is as follows:

switch(expression) {
    case v1:     
            actions1;
            break;
    case v2:     
            actions2;
            break;
         . .. .. .. .. ..
    default:     otherwise_actions;
}

notes

  • The value of the control expression can only be an integer or a character.
  • The control expression is enclosed in parentheses.
  • The default clause may be omitted.
  • The values viare possible values of the expression. If the expression evaluates to vi, the actions following the case viclause are executed.
  • The break statement exits the case structure. If it is absent at the end of the instruction block for value vi, execution then continues with the instructions for value vi+1.

example

In algorithms

depending on the selected value
Case 0
          stop
      case 1
    execute module M1
  case 2
    execute module M2
  else
    error<--true
end case

In Java


    int choice, error;
    switch(choice){   
        case 0: System.exit(0);
      case 1: M1();break;
      case 2: M2();break;
      default: error = 1;
     }

2.4.4. Loop structure

2.4.4.1. Known number of repetitions

Syntax


    for (i=id; i <= if; i = i + ip) { 
       actions; 
      } 

Notes

  • The three arguments of the for loop are enclosed in parentheses.
  • The three arguments of the for loop are separated by semicolons.
  • Each action in the for loop is terminated by a semicolon.
  • The curly brace is only necessary if there is more than one action.
  • The curly brace is not followed by a semicolon.

The algorithmic equivalent is the for structure:

for i ranging from id to if with a step of ip
        actions
endfor

which can be translated into a while structure:

    i id
    as long as i <= if
        actions
        i idwhile i <= if
    fintantque

2.4.4.2. Number of repetitions unknown

There are many control structures in Java for this case.

While loop


    while(condition){
          actions;
        } 

The loop continues as long as the condition is true. The loop may never be executed.

Notes:

  • The condition is enclosed in parentheses.
  • Each action is terminated by a semicolon.
  • Curly braces are only necessary if there is more than one action.
  • The curly brace is not followed by a semicolon.

The corresponding algorithmic structure is the while structure:

while condition
        actions
end-while

Do-while structure

The syntax is as follows:


    do{
       statements;
    }while(condition); 

The loop continues until the condition becomes false or as long as the condition is true. Here, the loop is executed at least once.

Notes

  • The condition is enclosed in parentheses.
  • Each action is terminated by a semicolon.
  • Curly braces are only necessary if there is more than one action.
  • The curly brace is not followed by a semicolon.

The corresponding algorithmic structure is the "repeat ... until" structure:

repeat
    actions
until condition

Structure for general (for)

The syntax is as follows:


for(start_statements;condition;end_statements){
    statements; 
}

The loop continues as long as the condition is true (evaluated before each iteration). Start_instructions are executed before entering the loop for the first time. End_loop_instructions are executed after each iteration.

Notes

  • The three arguments of the for loop are enclosed in parentheses.
  • The three arguments of the for loop are separated by semicolons.
  • Each for statement is terminated by a semicolon.
  • The curly brace is only necessary if there is more than one action.
  • The curly brace is not followed by a semicolon.
  • The various statements in start_statements and end_loop_statements are separated by commas.

The corresponding algorithmic structure is as follows:

start_instructions
while condition
        actions
        end_loop_instructions
end_while

Examples

The following programs all calculate the sum of the first n integers.


1   for(i=1, sum=0; i<=n; i=i+1)
        sum = sum + a[i];

2     for (i=1, sum=0; i<=n; sum=sum+a[i], i=i+1);

3    i=1; sum=0;
    while(i <= n)
       { sum += i; i++; }

4    i=1; sum=0;
    do sum += i++;
         while (i <= n);

Loop control statements

break
Exits the for, while, or do...while loop.
continue
moves to the next iteration of for, while, and do...while loops

2.5. The Structure of a Java Program

A Java program that does not use user-defined classes or functions other than the main function may have the following structure:


public class test1{
    public static void main(String arg[]){
        … program code
    }// main
}// class

The main function, also known as a method, is the first to be executed when running a Java program. It must have the following signature:


    public static void main(String arg[]){

or


    public static void main(String[] arg){

The name of the arg argument can be anything. It is an array of strings representing the command-line arguments. We will return to this later.

If you use functions that may throw exceptions you do not wish to handle explicitly, you can wrap the program code in a try/catch block:


public class test1{
    public static void main(String arg[]){
        try{
        … program code
        } catch (Exception e){
            // error handling
        }// try
    }// main
}// class

At the beginning of the source code and before the class definition, it is common to find class import statements. For example:


import java.io.*;
public class test1{
    public static void main(String arg[]){
        … program code
    }// main
}// class

Let's take an example. Consider the following write statement:

System.out.println("java");

which prints "java" to the screen. There is a lot going on in this simple statement:

  • System is a class whose full name is java.lang.System
  • out is a property of this class of type java.io.PrintStream, another class
  • println is a method of the java.io.PrintStream class.

We won’t unnecessarily complicate this explanation, which comes too early since it requires an understanding of the concept of a class that hasn’t been covered yet. A class can be thought of as a resource. Here, the compiler will need access to both the java.lang.System and java.io.PrintStream classes. The hundreds of Java classes are organized into archives also known as packages. The import statements placed at the beginning of the program are used to tell the compiler which external classes the program needs (those used but not defined in the source file to be compiled). Thus, in our example, our program needs the java.lang.System and java.io.PrintStream classes. We specify this with the import statement. We could write at the beginning of the program:

import java.lang.System;
import java.io.PrintStream;

Since a Java program commonly uses dozens of external classes, it would be tedious to write all the necessary import statements. Classes have been grouped into packages, and we can import the entire package. Thus, to import the java.lang and java.io packages, we write:

import java.lang.*;
import java.io.*;

The java.lang package contains all of Java’s base classes and is automatically imported by the compiler. So ultimately, we’ll just write:

import java.io.*;

2.6. Exception Handling

Many Java functions are capable of generating exceptions, i.e., errors. We have already encountered such a function, the readLine function:


String line = null;
try{
      line = IN.readLine();
      System.out.println("line=" + line);
    } catch (Exception e) {
      display(e);
      System.exit(2);
}// try

When a function is likely to throw an exception, the Java compiler requires the programmer to handle it in order to produce more error-resistant programs: you must always avoid an application "crashing" unexpectedly. Here, the readLine function throws an exception if there is nothing to read—for example, because the input stream has been closed. Exception handling follows this pattern:

try{
    function call that may throw an exception
} catch (Exception e){
    handle exception e
}
next statement

If the function does not throw an exception, the program proceeds to the next statement; otherwise, it enters the body of the catch clause and then proceeds to the next statement. Note the following points:

  • e is an object derived from the Exception type. We can be more specific by using types such as IOException, SecurityException, ArithmeticException, etc.: there are about twenty types of exceptions. By writing catch (Exception e), we indicate that we want to handle all types of exceptions. If the code in the try block is likely to generate multiple types of exceptions, we may want to be more specific by handling the exception with multiple catch blocks:

try{
    function call that may generate the exception
} catch (IOException e){
    handle exception e
}
} catch (ArrayIndexOutOfBoundsException e){
    handle exception e
}
} catch (RunTimeException e){
    handle exception e
}
next statement
  • A finally clause can be added to try/catch blocks:
try{
    call to the function that may generate the exception
} catch (Exception e){
    handle the exception e
}
finally{
    code executed after try or catch
}
next statement

Here, whether an exception occurs or not, the code in the finally clause will always be executed.

  • The Exception class has a getMessage() method that returns a message detailing the error that occurred. So if we want to display this message, we write:
catch (Exception ex){
    System.err.println("The following error occurred: " + ex.getMessage());
    ...
}//catch
  • The Exception class has a toString() method that returns a string indicating the exception type and the value of the Message property. We can therefore write:
catch (Exception ex) {
    System.err.println("The following error occurred: " + ex.toString());
    ...
}//catch

We can also write:

catch (Exception ex) {
    System.err.println("The following error occurred: " + ex);
    ...
}//catch

Here we have a string + Exception operation that will be automatically converted to string + Exception.toString() by the compiler in order to concatenate two strings.

The following example shows an exception generated by using a non-existent array element:

// arrays

// imports
import java.io.*;

public class tab1{
  public static void main(String[] args){
    // declaring and initializing an array
    int[] tab = new int[] {0, 1, 2, 3};
    int i;
    // Display the array using a for loop
    for (i=0; i<tab.length; i++)
      System.out.println("tab[" + i + "]=" + tab[i]);
    // Generate an exception
      try{
      tab[100] = 6;
    } catch (Exception e) {
      System.err.println("The following error occurred: " + e);
    }//try-catch
  }//main
}//class

Running the program produces the following results:

tab[0]=0
tab[1]=1
tab[2]=2
tab[3]=3
The following error occurred: java.lang.ArrayIndexOutOfBoundsException

Here is another example where we handle the exception caused by assigning a string to a number when the string does not represent a number:

// imports
import java.io.*;

public class console1{
  public static void main(String[] args){
      // create an input stream
    BufferedReader IN = null;
    try{
        IN = new BufferedReader(new InputStreamReader(System.in));
    } catch (Exception ex) {}
    // Ask for the name
    System.out.print("Name: ");
    // Read response
    String name = null;
    try{
        name = IN.readLine();
    } catch (Exception ex) {}      
    // Ask for age
    int age = 0;
    boolean ageOK = false;
    while ( ! ageOK) {
      // question
      System.out.print("age: ");
      // read and verify response
      try{
        age = Integer.parseInt(IN.readLine());
        ageOK = true;
      } catch (Exception ex) {
        System.err.println("Incorrect age, please try again...");
      }//try-catch
    }//while
    // final output
    System.out.println("Your name is " + name + " and you are " + age + " years old");
  }//Main
}//class

Some execution results:

dos>java console1
Name: dupont
age: 23
Your name is Dupont and you are 23 years old
E:\data\serge\MSNET\c#\bases\1>console1
Name: dupont
Age: xx
Incorrect age, please try again...
Age: 12
Your name is Dupont and you are 12 years old

2.7. Compiling and running a Java program

Compile and then run the following program:

// importing classes
import java.io.*;

// test class
public class hello{
    // main function
  public static void main(String args[]){
      // display on screen
    System.out.println("hello");
  }//main
}//class

The source file containing the previous coucou class must be named coucou.java:

E:\data\serge\JAVA\ESSAIS\intro1>dir
06/10/2002  08:42                  228 coucou.java

Compiling and running a Java program is done in a DOS window. The executables javac.exe (compiler) and java.exe (interpreter) are located in the bin directory of the JDK installation directory:

E:\data\serge\JAVA\classes\packages\person>dir "e:\program files\jdk14\bin\java?.exe"
02/07/2002  12:52               24,649 java.exe
02/07/2002  12:52               28,766 javac.exe

The javac.exe compiler will analyze the .java source file and produce a compiled .class file. This file is not immediately executable by the processor. It requires a Java interpreter (java.exe), known as a virtual machine or JVM (Java Virtual Machine). From the intermediate code in the .class file, the virtual machine generates instructions specific to the processor of the machine on which it is running. There are Java virtual machines for different types of operating systems (Windows, Unix, Mac OS, etc.). A .class file can be executed by any of these virtual machines and therefore on any operating system. This cross-system portability is one of Java’s major strengths.

Let’s compile the previous program:

E:\data\serge\JAVA\ESSAIS\intro1>"e:\program files\jdk14\bin\javac" coucou.java

E:\data\serge\JAVA\ESSAIS\intro1>dir
06/10/2002  08:42                  228 hello.java
10/06/2002  08:48                  403 hello.class

Let's run the generated .class file:

E:\data\serge\JAVA\ESSAIS\intro1>"e:\program files\jdk14\bin\java" hello
hello

Note that in the execution command above, we did not specify the .class suffix for the coucou.class file to be executed. It is implied. If the JDK's bin directory is in the DOS machine's PATH, we do not need to provide the full path to the javac.exe and java.exe executables. We can simply write

javac hello.java
java hello

2.8. Main Program Arguments

The main function accepts an array of strings as parameters: String[]. This array contains the command-line arguments used to launch the application. Thus, if we launch the program P with the command:

        java P arg0 arg1 … argn

and if the main function is declared as follows:

public static void main(String[] arg);

we will have arg[0]="arg0", arg[1]="arg1" … Here is an example:


import java.io.*;

public class param1{
  public static void main(String[] arg){
    int i;
    System.out.println("Number of arguments="+arg.length);
    for (i=0; i<arg.length; i++)
      System.out.println("arg[" + i + "] = " + arg[i]);
  }
}

The results are as follows:

dos>java param1 a b c
Number of arguments=3
arg[0]=a
arg[1] = b
arg[2] = c

2.9. Passing Parameters to a Function

The previous examples showed only Java programs with a single function, the main function. The following example demonstrates how to use functions and how information is exchanged between them. Function parameters are always passed by value: that is, the value of the actual parameter is copied into the corresponding formal parameter.


import java.io.*;

public class param2{
  public static void main(String[] arg){
    String S = "dad";
    changeString(S);
    System.out.println("Actual parameter S=" + S);
    int age = 20;
    changeInt(age);
    System.out.println("Actual parameter age=" + age);
  }
  private static void changeString(String S) {
    S = "mom";
    System.out.println("Formal parameter S=" + S);
  }
  private static void changeInt(int a) {
    a = 30;
    System.out.println("Formal parameter a="+a);
  }
}

The results obtained are as follows:

Formal parameter S=mom
Actual parameter S=dad
Formal parameter a=30
Actual parameter age=20

The values of the actual parameters "dad" and 20 were copied into the formal parameters S and a. These were then modified. The actual parameters remained unchanged. Note here the type of the actual parameters:

  • S is an object reference, i.e., the address of an object in memory
  • age is an integer

2.10. An example of a tax calculation

We will conclude this chapter with an example that we will revisit several times in this document. We propose to write a program to calculate a taxpayer’s tax. We consider the simplified case of a taxpayer who has only their salary to report:

  • we calculate the number of tax brackets for the employee as nbParts = nbEnfants / 2 + 1 if they are unmarried, and nbEnfants / 2 + 2 if they are married, where nbEnfants is the number of children.
  • If they have at least three children, they receive an additional half-share.
  • We calculate taxable income R = 0.72 × S, where S is annual salary
  • We calculate the family coefficient QF = R / nbParts
  • We calculate your tax I. Consider the following table:
12,620.0
0
0
13,190
0.05
631
15,640
0.1
1,290.5
24,740
0.15
2,072.5
31,810
0.2
3,309.5
39,970
0.25
4,900
48,360
0.3
6,898.5
55,790
0.35
9,316.5
92,970
0.4
12,106
127,860
0.45
16,754.5
151,250
0.50
23,147.5
172,040
0.55
30,710
195,000
0.60
39,312
0
0.65
49,062

Each row has 3 fields. To calculate tax I, we look for the first row where QF <= field1. For example, if QF = 23,000, we will find the row

    24740        0.15        2072.5

Tax I is then equal to 0.15*R - 2072.5*nbParts. If QF is such that the condition QF<=field1 is never met, then the coefficients from the last row are used. Here:

    0                0.65        49062

which gives the tax I = 0.65*R - 49062*nbParts.

The corresponding Java program is as follows:


import java.io.*;

public class taxes{

    // ------------ main
    public static void main(String arg[]){

        // data

        // tax bracket limits
        double Limits[] = {12620, 13190, 15640, 24740, 31810, 39970, 48360, 55790, 92970, 127860, 151250, 172040, 195000, 0};    
        // coefficient applied to the number of shares
        double Coeffn[]={0, 631, 1290.5, 2072.5, 3309.5, 4900, 6898.5, 9316.5, 12106, 16754.5, 23147.5, 30710, 39312, 49062};

        // the program

        // create keyboard input stream
        BufferedReader IN = null;
        try{
            IN = new BufferedReader(new InputStreamReader(System.in));
        }
        catch (Exception e) {
            error("Creating input stream", e, 1);
        }

            // retrieve marital status
        boolean OK = false;
        String response = null;
        while(!OK){
            try{
                System.out.print("Are you married (Y/N)?");
                response = IN.readLine();
                response = response.trim().toLowerCase();
                if (!response.equals("y") && !response.equals("n"))
                    System.out.println("Incorrect answer. Please try again");
                else OK = true;
            } catch(Exception e){
                error("Reading marital status", e, 2);
            }
        }
        boolean Marie = response.equals("o");

            // number of children
        OK = false;
        int numberOfChildren = 0; 
        while(! OK){
            try{
                System.out.print("Number of children: ");
                response = IN.readLine();
                try{
                    numberOfChildren = Integer.parseInt(response);
                    if(NumberOfChildren >= 0) OK = true; 
                        else System.err.println("Incorrect answer. Please try again");
                } catch (Exception e) {
                    System.err.println("Incorrect answer. Please try again");
                }// try
            } catch (Exception e) {
                error("Reading marital status", e, 2);
            }// try
        }// while

        // salary
        OK = false;
        long Salary = 0; 
        while(! OK){
            try{
                System.out.print("Annual salary: ");
                response = IN.readLine();
                try{
                    Salary = Long.parseLong(response);
                    if(Salary >= 0)  OK = true;
                        else System.err.println("Incorrect answer. Please try again");
                } catch (Exception e) {
                    System.err.println("Incorrect answer. Please try again");
                }// try
            } catch (Exception e) {
                error("Read Salary", e, 4);
            }// try
        }// while

            // Calculate the number of shares
        double NbParts;
        if(Marie) NbParts=(double)NbChildren/2+2;
            else NbParts = (double)NbChildren / 2 + 1;
        if (NbChildren >= 3) NbParts += 0.5;
        
            // taxable income
        double Income;
        Income = 0.72 * Salary;

            // family quotient
        double FamilyQuotient;
        QF = Income / NumberOfShares;
        
            // find the tax bracket corresponding to QF
        int i;
        int NumberOfBrackets = Limits.length;
        Limits[NbTranches-1] = QF;
        i = 0;
        while (QF > Limits[i]) i++;
            // tax
        long tax = (long)(i * 0.05 * Income - Coeffn[i] * NbParts);

        // display the result
        System.out.println("Tax due: " + tax);
    }// main

    // ------------ error
    private static void error(String msg, Exception e, int exitCode){
        System.err.println(msg + "(" + e + ")");
        System.exit(exitCode);
    }// error

}// class

The results obtained are as follows:

C:\Serge\java\impots\1>java impots

Are you married (Y/N)? y
Number of children: 3
Annual salary: 200,000
Tax due: 16,400

C:\Serge\java\taxes\1>java taxes

Are you married (Y/N)? n
Number of children: 2
Annual income: 200,000
Tax due: 33,388

C:\Serge\java\impots\1>java impots

Are you married (Y/N)? w
Incorrect answer. Please try again
Are you married (Y/N)? q
Incorrect answer. Try again
Are you married (Y/N)? y
Number of children: q
Incorrect answer. Please try again
Number of children: 2
Annual income: q
Incorrect answer. Please try again
Annual income: 1
Tax due: 0