Skip to content

2. The Basics 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 types of 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
Domain
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
[-215, 215-1]
float
4 bytes
[3.4 10-38, 3.4 10+38] absolute value
double
8 bytes
[1.7 10-308 , 1.7 10+308] as 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:

final type name=value; //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 taux_tva=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 taux_tva=0.33F;

If we had used 0.186 explicitly in the program, we would have had to change many lines of code.

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 digits. 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:

identificateur_de_type variable1,variable2,...,variablen;

where identificateur_de_type 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 demonstrating 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 generates a fatal error called an exception in Java. This error can be handled by the following try/catch block:

try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
instruction suivante

If the function does not throw an exception, we proceed to the next statement; otherwise, we enter the body of the catch clause and then proceed 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;
    affiche(S);
    S=""+l;
    affiche(S);
    S=""+f;
    affiche(S);
    S=""+d;
    affiche(S);
 
    //boolean --> string
    final boolean b=false;
    S=""+new Boolean(b);
    affiche(S);
 
    // string --> int
    int i1;
    i1=Integer.parseInt("10");
    affiche(""+i1);
    try{
      i1=Integer.parseInt("10.67");
      affiche(""+i1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }
 
    // string --> long
    long l1;
    l1=Long.parseLong("100");
    affiche(""+l1);
    try{
      l1=Long.parseLong("10.675");
      affiche(""+l1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }
    
    // chain --> double
    double d1;
    d1=Double.valueOf("100.87").doubleValue();
    affiche(""+d1);
    try{
      d1=Double.valueOf("abcd").doubleValue();
      affiche(""+d1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }
 
    // string --> float
    float f1;
    f1=Float.valueOf("100.87").floatValue();
    affiche(""+f1);
    try{
      d1=Float.valueOf("abcd").floatValue();
      affiche(""+f1);
    } catch (Exception e){
      affiche("Erreur "+e);
    }
 
}// fine hand
 
  public static void affiche(String S){
    System.out.println("S="+S);
  }
}// end of class

The results are as follows:

S=10
S=100000
S=45.78
S=-14.98
S=false
S=10
S=Erreur java.lang.NumberFormatException: 10.67
S=100
S=Erreur java.lang.NumberFormatException: 10.675
S=100.87
S=Erreur java.lang.NumberFormatException: abcd
S=100.87
S=Erreur 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 data elements the array can contain. The syntax Array[i] refers to the data element at index i, where i belongs to the range [0,n-1]. Any reference to the data Array[i] where i does not belong to the interval [0,n-1] will cause an exception.

A two-dimensional array can be declared as follows:

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

The syntax Table[i] refers to data entry number i in Table[0,n-1], where i belongs to the range [0,n-1]. Table[i] is itself a table: Table[i][j] refers to data item #j in Table[i], where j belongs to the range [0,p-1]. Any reference to data in Table[i] with incorrect indices generates a fatal error.

Here is an example:


public class test1{
 
  public static void main(String arg[]){
    float[][] taux=new float[2][2];
    taux[1][0]=0.24F;
    taux[1][1]=0.33F;
    System.out.println(taux[1].length);
    System.out.println(taux[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 statements

We distinguish

  • between 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 write 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 for display on the screen. In the previous example, we saw two print statements:

System.out.println(taux[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:

    commande1 | commande2

Everything that command1 writes to System.out is piped (redirected) to the input of command2 via System.in. 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 setup, 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 will 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 entered via the keyboard

The data stream from the keyboard is represented by the object System.in of type InputStream. This type of object allows data to be read character by character. It is up to the programmer to then find the information of interest within this character stream. The InputStream type does not allow reading a line of text in a single operation. The BufferedReader type allows this using the readLine method.

To read lines of text typed on the keyboard, we create another 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, you must actually write:


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

Again, we will not attempt to explain exception handling here. Once the previous IN stream has been constructed, we can read a line of text using the statement:

    String ligne;
    ligne=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. Example of Input/Output

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


import java.io.*;        // required to use I/O streams
 
public class io1{
  
  
  public static void main (String[] arg){
    
    // write to System.out stream
    Object obj=new Object();
    System.out.println(""+obj);
    System.out.println(obj.getClass().getName());
    
    // write to System.err stream
    int i=10;
    System.err.println("i="+i);
    
    // read a line entered on the keyboard
    String ligne;
    BufferedReader IN=null;
    try{
      IN=new BufferedReader(new InputStreamReader(System.in));
    } catch (Exception e){
      affiche(e);
      System.exit(1);
    }
    System.out.print("Tapez une ligne : ");
    try{
      ligne=IN.readLine();
      System.out.println("ligne="+ligne);
    } catch (Exception e){
      affiche(e);
      System.exit(2);
    }
  }//fine hand
 
  public static void affiche(Exception e){
    System.err.println("Erreur : "+e);
  }
 
}//end of class

and the results of the execution:

C:\Serge\java\bases\iostream>java io1
java.lang.Object@1ee78b
java.lang.Object
i=10
Tapez une ligne : je suis là
ligne=je suis là

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){
      affiche(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, or 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 operation V1=V2=expression is valid. Due to precedence, the rightmost = operator is evaluated. We therefore have V1=(V2=expression). The expression V2=expression is evaluated and has the value V. The evaluation of this expression caused V to be assigned to V2. The next = operator is then evaluated in the form V1=V. The value of this expression is again 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 a real number. 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 type 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 where 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):

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

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

2.3.4.4. Relational operators

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

Order of precedence

>, >=, <, <=

==, !=

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

Example:

      boolean fin;
      int x;
      fin=x>4;

Comparison of two characters

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

<, <=, ==, !=, >, >=

. It is their codes ASCII—which are numbers—that are compared. Recall that according to the order ASCII, the following relations 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 implies an inequality of the same direction on 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

"Cat" < "Kitten".

Functions for comparing two strings

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

String chaine1, chaine2;
chaine1=…;
chaine2=…;
int i=chaine1.compareTo(chaine2);
boolean egal=chaine1.equals(chaine2)

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

0: if the two strings are equal

1: if string 1 > string 2

-1: if string 1 < string 2

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

2.3.4.5. Boolean expressions

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

Order of precedence ! , &&, ||

example:

int fin;
int x;
fin= 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
shift i n bits to the right. If i is a signed integer (signed char, int, long), the sign bit is preserved.
i & j
performs a bitwise logical OR of i and j.
i | j
performs a bitwise logical OR of i and j.
~i
complements i to 1
i^j
performs the OU EXCLUSIF operation on 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>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;   // priority of () over /

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 encoded as an approximate floating-point number over 4 bytes

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

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 value of status 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. On Unix, the $? variable retrieves the status value if the shell 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


 syntaxe :  if (condition) {actions_condition_vraie;} else {actions_condition_fausse;}

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 required 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:

si condition
  alors actions_condition_vraie
  sinon actions_conditions_fausse
finsi

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>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 from if(n>6): nothing to do 
   else System.out.println("<=1");    // else du 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 are no instructions.

2.4.3. Case structure

The syntax is as follows:

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

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 vi are possible values of the expression. If the expression evaluates to vi, the actions following the case vi clause are executed.
  • The break statement exits the case structure. If it is missing at the end of the instruction block corresponding to value vi, execution then continues with the instructions corresponding to value vi+1.

example

In algorithms

selon la valeur de choix
cas 0
          arrêt
      cas 1
    exécuter module M1
  cas 2
    exécuter module M2
  sinon
    erreur<--real
findescas

In Java


    int choix, erreur;
    switch(choix){   
        case 0: System.exit(0);
      case 1: M1();break;
      case 2: M2();break;
      default: erreur=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 3 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 loop:

pour i variant de id à if avec un pas de ip
        actions
finpour

which can be translated into a while structure:

    i  id
    tantque i<=if
        actions
        i i+ip
    fintantque

2.4.4.2. Unknown number of repetitions

There are many 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:

tantque condition
        actions
fintantque

Do-while loop

The syntax is as follows:


    do{
       instructions;
    }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.
  • The curly brace is 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:

répéter
    actions
jusqu'provided

Structure for general (for)

The syntax is as follows:


for(instructions_départ;condition;instructions_fin_boucle){
    instructions; 
}

The loop continues as long as the condition is true (evaluated before each iteration). Instructions_départ are executed before entering the loop for the first time. Instructions_fin_boucle are executed after each iteration.

notes

  • The 3 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 various statements in instructions_depart and instructions_fin_boucle are separated by commas.

The corresponding algorithmic structure is as follows:

instructions_départ
tantque condition
        actions
        instructions_fin_boucle
fintantque

Examples

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


1  for(i=1, somme=0;i<=n;i=i+1)
        somme=somme+a[i];
 
2     for (i=1, somme=0;i<=n;somme=somme+a[i], i=i+1);
 
3    i=1;somme=0;
    while(i<=n)
       { somme+=i; i++; }
 
4    i=1; somme=0;
    do somme+=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[]){
        … code du programme
    }// hand
}// 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{
        … code du programme
        } catch (Exception e){
            // error handling
        }// try
    }// hand
}// 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[]){
        … code du programme
    }// hand
}// 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 the two classes java.lang.System and java.io.PrintStream. 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 classes java.lang.System and java.io.PrintStream. 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 packages java.lang and java.io, we write:

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

The java.lang package contains all the Java base classes and is automatically imported by the compiler. So ultimately, we will only 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 ligne=null;
try{
      ligne=IN.readLine();
      System.out.println("ligne="+ligne);
    } catch (Exception e){
      affiche(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-tolerant programs: you should always avoid an application "crashing" unexpectedly. Here, the function readLine throws an exception if there is nothing to read—for example, because the input stream has been closed. Exception handling follows this pattern:

try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
instruction suivante

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

  • e is an object derived from the Exception type. You 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{
    appel de la fonction susceptible de générer l'exception
} catch (IOException e){
    traiter l'exception e
}
} catch (ArrayIndexOutOfBoundsException e){
    traiter l'exception e
}
} catch (RunTimeException e){
    traiter l'exception e
}
instruction suivante
  • You can add a finally clause to try/catch blocks:
try{
    appel de la fonction susceptible de générer l'exception
} catch (Exception e){
    traiter l'exception e
}
finally{
    code exécuté après try ou catch
}
instruction suivante

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

  • The Exception class has a method getMessage() 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("L'erreur suivante s'est produite : "+ex.getMessage());
    ...
}//catch
  • The Exception class has a method toString() that returns a string indicating the exception type as well as the value of the Message property. You can therefore write:
catch (Exception ex){
    System.err.println ("L'erreur suivante s'est produite : "+ex.toString());
    ...
}//catch

We can also write:

catch (Exception ex){
    System.err.println ("L'erreur suivante s'est produite : "+ex);
    ...
}//catch

Here we have an operation string + Exception, which 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:

// tables

// imports
import java.io.*;

public class tab1{
  public static void main(String[] args){
    // declaring & initializing an array
    int[] tab=new int[] {0,1,2,3};
    int i;
     // table display with for
    for (i=0; i<tab.length; i++)
      System.out.println("tab[" + i + "]=" + tab[i]);
    // generating an exception
      try{
      tab[100]=6;
    }catch (Exception e){
      System.err.println("L'erreur suivante s'est produite : " + e);
    }//try-catch
  }//hand
}//class

Running the program produces the following results:

tab[0]=0
tab[1]=1
tab[2]=2
tab[3]=3
L'the following error has 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){
      // creation of an input stream
    BufferedReader IN=null;
    try{
        IN=new BufferedReader(new InputStreamReader(System.in));
    }catch(Exception ex){}
     // We ask for the name
    System.out.print("Nom : ");
     // reading response
    String nom=null;
    try{
        nom=IN.readLine();
    }catch(Exception ex){}      
     // age requested
    int age=0;
    boolean ageOK=false;
    while ( ! ageOK){
       // question
      System.out.print("âge : ");
       // read-verify answer
      try{
        age=Integer.parseInt(IN.readLine());
        ageOK=true;
      }catch(Exception ex) {
        System.err.println("Age incorrect, recommencez...");
      }//try-catch
    }//while
     // final display
    System.out.println("Vous vous appelez " + nom + " et vous avez " + age + " ans");
  }//Main
}//class

Some execution results:

dos>java console1
Nom : dupont
âge : 23
Vous vous appelez dupont et vous avez 23 ans
E:\data\serge\MSNET\c#\bases\1>console1
Nom : dupont
âge : xx
Age incorrect, recommencez...
âge : 12
Vous vous appelez dupont et vous avez 12 ans

2.7. Compiling and Running a Java Program

Compile and then run the following program:

// importing classes
import java.io.*;

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

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

E:\data\serge\JAVA\ESSAIS\intro1>dir
10/06/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\paquetages\personne>dir "e:\program files\jdk14\bin\java?.exe"
07/02/2002  12:52               24 649 java.exe
07/02/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 present in the .class file, the virtual machine will generate instructions specific to the processor of the machine on which it is running. There are Java virtual machines for various 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
10/06/2002  08:42                  228 coucou.java
10/06/2002  08:48                  403 coucou.class

Let's run the generated .class file:

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

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 bin directory of JDK is located in PATH on the machine DOS, you do not need to specify the full path for the javac.exe and java.exe executables. You can simply write

javac coucou.java
java coucou

2.8. Main program arguments

The main function main accepts as parameters an array of strings: *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("Nombre d'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
Nombre d'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="papa";
    changeString(S);
    System.out.println("Paramètre effectif S="+S);
    int age=20;
    changeInt(age);
    System.out.println("Paramètre effectif age="+age);
  }
  private static void changeString(String S){
    S="maman";
    System.out.println("Paramètre formel S="+S);
  }
  private static void changeInt(int a){
    a=30;
    System.out.println("Paramètre formel a="+a);
  }
}

The results obtained are as follows:

Paramètre formel S=maman
Paramètre effectif S=papa
Paramètre formel a=30
Paramètre effectif 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 c.a.d. The address of an object in memory
  • age is an integer

2.10. The Tax Example

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 a single salary to report:

  • we calculate the number of shares for the employee nbParts=nbEnfants/2 +1 if they are unmarried, nbEnfants/2+2 if they are married, where nbEnfants is the number of their children.
  • if he has at least three children, he has an additional half-share
  • his taxable income is calculated as R=0.72*S, where S is his annual salary
  • we calculate his family coefficient QF = R / nbParts
  • We calculate his 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
4900
48,360
0.3
6898.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
39312
0
0.65
49062

Each row has 3 fields. To calculate tax I, we look for the first row where QF <= field1. For example, if QF = 23000, 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 relationship QF<=field1 is never satisfied, then the coefficients of the last line 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 impots{
 
    // ------------ hand
    public static void main(String arg[]){
 
        // data
 
        // tax bracket limits
        double Limites[]={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
 
        // keyboard input stream creation
        BufferedReader IN=null;
        try{
            IN=new BufferedReader(new InputStreamReader(System.in));
        }
        catch(Exception e){
            erreur("Création du flux d'entrée", e, 1);
        }
 
            // marital status is restored
        boolean OK=false;
        String reponse=null;
        while(! OK){
            try{
                System.out.print("Etes-vous marié(e) (O/N) ? ");
                reponse=IN.readLine();
                reponse=reponse.trim().toLowerCase();
                if (! reponse.equals("o") && !reponse.equals("n"))
                    System.out.println("Réponse incorrecte. Recommencez");
                else OK=true;
            } catch(Exception e){
                erreur("Lecture état marital",e,2);
            }
        }
        boolean Marie = reponse.equals("o");
 
            // number of children
        OK=false;
        int NbEnfants=0; 
        while(! OK){
            try{
                System.out.print("Nombre d'enfants : ");
                reponse=IN.readLine();
                try{
                    NbEnfants=Integer.parseInt(reponse);
                    if(NbEnfants>=0) OK=true; 
                        else System.err.println("Réponse incorrecte. Recommencez");
                } catch(Exception e){
                    System.err.println("Réponse incorrecte. Recommencez");
                }// try
            } catch(Exception e){
                erreur("Lecture état marital",e,2);
            }// try
        }// while
 
        // salary
        OK=false;
        long Salaire=0; 
        while(! OK){
            try{
                System.out.print("Salaire annuel : ");
                reponse=IN.readLine();
                try{
                    Salaire=Long.parseLong(reponse);
                    if(Salaire>=0)  OK=true;
                        else System.err.println("Réponse incorrecte. Recommencez");
                } catch(Exception e){
                    System.err.println("Réponse incorrecte. Recommencez");
                }// try
            } catch(Exception e){
                erreur("Lecture Salaire",e,4);
            }// try
        }// while
 
            // calculating the number of shares
        double NbParts;
        if(Marie) NbParts=(double)NbEnfants/2+2;
            else NbParts=(double)NbEnfants/2+1;
        if (NbEnfants>=3) NbParts+=0.5;
 
            // taxable income
        double Revenu;
        Revenu=0.72*Salaire;
 
            // family quotient
        double QF;
        QF=Revenu/NbParts;
 
            // search for tax bracket corresponding to QF
        int i;
        int NbTranches=Limites.length;
        Limites[NbTranches-1]=QF;
        i=0;
        while(QF>Limites[i]) i++;
            // tax
        long impots=(long)(i*0.05*Revenu-Coeffn[i]*NbParts);
 
        // the result is displayed
        System.out.println("Impôt à payer : " + impots);
    }// hand
 
    // ------------ error
    private static void erreur(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

Etes-vous marié(e) (O/N) ? o
Nombre d'children: 3
Salaire annuel : 200000
Impôt à payer : 16400

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

Etes-vous marié(e) (O/N) ? n
Nombre d'children: 2
Salaire annuel : 200000
Impôt à payer : 33388

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

Etes-vous marié(e) (O/N) ? w
Réponse incorrecte. Recommencez
Etes-vous marié(e) (O/N) ? q
Réponse incorrecte. Recommencez
Etes-vous marié(e) (O/N) ? o
Nombre d'children: q
Réponse incorrecte. Recommencez
Nombre d'children: 2
Salaire annuel : q
Réponse incorrecte. Recommencez
Salaire annuel : 1
Impôt à payer : 0