Les instructions (en anglais statement) ont pour rôle d'opérer sur la mémoire et de contrôler l'exécution du programme. Celles-ci ne peuvent figurer que dans le corps d'une fonction (ou dans un bloc statique). Une instruction est soit une instruction simple, soit une instruction composée. Voici des instructions simples (d'autres catégories seront présentées ultérieurement) :
Il arrive souvent
que l'on affecte à une variable le résultat d'une opération binaire
entre celle-ci et une autre expression :
.
Il est alors possible d'avoir recours à la notation abrégée:
. On écrira ainsi :
x+=y
au lieu de
x=x+y
et x/=2
au lieu de x=x/2
. Outre la
simplification d'écriture, l'utilisation de cette syntaxe peut avoir des
effets importants sur le comportement et l'efficacité du programme.
{ int t = x%y; x = y; y = t; }
Notons que le corps d'une fonction est un bloc et qu'un bloc peut être
vide, ce qu'on écrit simplement {}
.
La portée d'un nom de variable locale s'étend à tout le bloc où ce nom est déclaré :
{ { int n = 2; } p = n; // hors de la portée de la déclaration précédente }
Notons qu'il est illégal de déclarer une variable locale de même nom qu'un paramètre, de déclarer plusieurs fois la même variable locale dans un même bloc ou dans un bloc imbriqué, et cela même si les types sont distincts :
static void f(int x) { char x; // ILLÉGAL : x est déjà un paramètre int n = 3; int n; // ILLÉGAL : n est déjà une variable locale { double n = 4; // ILLÉGAL : n est déjà une variable locale } }
Un même nom peut apparaître à plusieurs endroits dans un programme : on parle des occurrences de ce nom. Il y a une et une seule occurrence de déclaration, dans sa portée, et des occurrences d'utilisation. Quand on voit une occurrence d'utilisation d'un nom, il faut pouvoir remonter à sa déclaration :
int n = 2; // occurrence de déclaration de n // ... p = n; // occurrence d'utilisation de n
La description des opérations réalisées lors de l'invocation d'une fonction spécifie la relation entre l'argument, qui figure dans l'expression d'invocation, et le paramètre correspondant, qui figure dans la définition de la fonction : pour chaque paramètre d'une fonction, et pour chaque invocation, il y a création d'une variable dans son cadre d'invocation et initialisation de cette variable par la valeur de l'argument correspondant. Les affectations à un paramètre ne peuvent donc pas modifier la valeur de l'argument correspondant quand cet argument est une variable. Par exemple, la procédure PassageParValeur.test suivante, après avoir initialisé le paramètre x à la valeur de l'argument n, lui affecte 0 (et n'en fait rien d'utilisable), mais ne modifie évidemment pas n, variable locale de PassageParValeur.main :
package exemples; class PassageParValeur { static void test(int x) { x = 0; } public static void main(String[] args) { int n = 4; test(n); // n n'est pas modifiée System.out.println("n = " + n); // --> n = 4 } }
package exemples; class FonctionImperative { static int état = 0; static int f(int x) { état++; return x + état; } public static void main(String[] args) { System.out.println("f(0) = " + f(0)); // --> f(0) = 1 System.out.println("f(0) = " + f(0)); // --> f(0) = 2 System.out.println("f(0) = " + f(0)); // --> f(0) = 3 } }
La propriété caractéristique du style applicatif (la valeur d'une expression ne dépend que des valeurs des sous-expressions et de l'opération qui les combine) n'est donc plus valable.