Essayer de coder ← Retour aux sujets

Définir et appeler

static

Une méthode a un type de retour, un nom et des paramètres typés. Dans un programme sans objets, on les déclare static, dans la même classe que main.

static int carre(int x) { return x * x; }
Définition : renvoie un int
static void saluer() { … }
Ne renvoie rien (void)
int y = carre(5);
Appel : y reçoit 25
static int max(int a, int b)
Surcharge : même nom, paramètres différents
return;
Quitte immédiatement une méthode void
Carre.java
public class Carre {
    static int carre(int x) {
        return x * x;
    }

    public static void main(String[] args) {
        System.out.println(carre(7));
        System.out.println(carre(carre(2)));
    }
}
Affichage
49
16

Valeur ou référence ?

passage

Java passe toujours une copie. Pour un nombre, c'est sa valeur ; pour un tableau ou un objet, c'est la copie de sa référence : la méthode peut modifier l'objet, mais pas changer la variable de l'appelant.

void f(int n)
n est une copie : l'appelant ne voit rien
void f(int[] t)
t désigne le même tableau que l'appelant
t[0] = 99; (dans f)
Visible depuis l'appelant
t = new int[3]; (dans f)
Invisible : on change la copie de la référence
static int compteur = 0;
Variable partagée par toute la classe
Passage.java
public class Passage {
    static void incremente(int n) {
        n = n + 1;                   // modifie la copie
    }

    static void remplit(int[] t) {
        t[0] = 99;                   // modifie le tableau partagé
        t = new int[3];              // ne change pas la variable de l'appelant
    }

    public static void main(String[] args) {
        int a = 5;
        int[] t = {1, 2, 3};

        incremente(a);
        remplit(t);
        System.out.println(a + " " + t[0] + " " + t.length);
    }
}
Affichage
5 99 3

📘 Le cours : découper en méthodes

Une méthode (une « fonction » en Java) regroupe du code nommé et réutilisable. Découper un programme en petites méthodes, chacune avec une seule mission, le rend plus lisible et plus simple à tester. Tu en utilises déjà : main, println, Math.sqrt.

Anatomie d'une méthode

static typeDeRetour nomDeLaMethode(type param1, type param2) {
    // corps de la méthode
    return valeur;          // du type annoncé
}
  • void signifie que la méthode ne renvoie rien ; sinon, tous les chemins d'exécution doivent se terminer par un return (le compilateur le vérifie).
  • Les paramètres sont des variables locales initialisées avec les valeurs de l'appel.
  • Par convention, les noms de méthodes sont en minuscules avec majuscule à chaque mot : calculerMoyenne.

Pourquoi static ?

main est static : il s'exécute sans qu'aucun objet n'existe. Depuis main, on ne peut appeler directement que des méthodes static de la même classe. Les méthodes qui travaillent sur un objet (sans static) sont vues dans POO.

Méthode sans résultat

Barre.java
public class Barre {
    static void barre(int longueur) {
        for (int i = 0; i < longueur; i++) {
            System.out.print("=");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        barre(10);
        System.out.println("NSI");
        barre(10);
    }
}
Affichage
==========
NSI
==========

Surcharge : même nom, paramètres différents

Java permet plusieurs méthodes de même nom si leurs paramètres diffèrent (nombre ou types). Le compilateur choisit la bonne d'après les arguments de l'appel. Le type de retour seul ne suffit pas à les distinguer.

Surcharge.java
public class Surcharge {
    static int max(int a, int b) {
        return (a > b) ? a : b;
    }

    static double max(double a, double b) {
        return (a > b) ? a : b;
    }

    static int max(int a, int b, int c) {
        return max(max(a, b), c);
    }

    public static void main(String[] args) {
        System.out.println(max(3, 8));
        System.out.println(max(2.5, 1.5));
        System.out.println(max(4, 9, 6));
    }
}
Affichage
8
2.5
9

Passage des arguments

Java ne connaît qu'un seul mode de passage : la copie. Mais copier une référence, c'est copier l'adresse d'un objet : la copie et l'original désignent le même objet. D'où le résultat de l'exemple de la deuxième carte : a n'a pas changé, t[0] a été modifié (le tableau est partagé), et t.length vaut toujours 3 (la réaffectation t = new int[3] ne concernait que la copie locale).

Renvoyer plusieurs valeurs

Une méthode ne renvoie qu'une valeur. Pour en rendre plusieurs, on renvoie un tableau (ou, plus proprement, un objet : voir POO).

Extremes.java
public class Extremes {
    static int[] extremes(int[] t) {
        int min = t[0];
        int max = t[0];
        for (int x : t) {
            if (x < min) min = x;
            if (x > max) max = x;
        }
        return new int[] {min, max};
    }

    public static void main(String[] args) {
        int[] notes = {12, 7, 15, 9};
        int[] res = extremes(notes);

        System.out.println("min = " + res[0] + ", max = " + res[1]);
    }
}
Affichage
min = 7, max = 15

Portée des variables

  • Une variable locale (dans une méthode, un bloc ou un for) n'existe que dans ce bloc.
  • Un paramètre vit le temps de l'appel.
  • Une variable static déclarée dans la classe (hors de toute méthode) est partagée par tous les appels et garde sa valeur entre eux.
Appels.java
public class Appels {
    static int appels = 0;          // partagée par toute la classe

    static int suivant() {
        appels++;
        return appels;
    }

    public static void main(String[] args) {
        System.out.println(suivant());
        System.out.println(suivant());
        System.out.println(suivant());
    }
}
Affichage
1
2
3

Récursivité

Une méthode récursive s'appelle elle-même. Il lui faut un cas de base qui arrête la récursion et un appel sur un cas plus petit. Sans cas de base, les appels s'empilent jusqu'à une StackOverflowError.

Factorielle.java
public class Factorielle {
    static long fact(int n) {
        if (n <= 1) {
            return 1;                    // cas de base
        }
        return n * fact(n - 1);          // appel sur un cas plus petit
    }

    public static void main(String[] args) {
        System.out.println(fact(5));
        System.out.println(fact(20));
    }
}
Affichage
120
2432902008176640000

Au-delà de 20!, un long déborde sans prévenir (complément à deux, voir Entiers signés).

Documenter avec Javadoc

Un commentaire /** … */ placé juste avant une méthode, avec @param et @return, est lu par les éditeurs (info-bulle) et par l'outil javadoc.

Documentee.java
/**
 * Calcule la moyenne de deux notes.
 *
 * @param a première note
 * @param b deuxième note
 * @return la moyenne, entre a et b
 */
static double moyenne(double a, double b) {
    return (a + b) / 2;
}

⚠️ Erreurs fréquentes

Appeler une méthode non static depuis main

À éviter
Faux.java
public class Faux {
    int carre(int x) { return x * x; }

    public static void main(String[] args) {
        System.out.println(carre(3));   // erreur de compilation
    }
}
Correct
Correct.java
public class Correct {
    static int carre(int x) { return x * x; }

    public static void main(String[] args) {
        System.out.println(carre(3));
    }
}

Le message est « non-static method carre(int) cannot be referenced from a static context ». Ajoute static à la méthode (ou crée un objet, voir la POO).

Oublier un return

Si un chemin d'exécution n'a pas de return alors que la méthode annonce un type, le compilateur refuse : « missing return statement ». Pense aux cas else qui manquent.

Croire qu'on modifie une variable primitive de l'appelant

Après incremente(a), a n'a pas changé : la méthode a travaillé sur une copie. Renvoie plutôt le résultat : a = incremente(a);.

Réaffecter un paramètre objet ou tableau

Écrire t = new int[3] dans une méthode ne change pas la variable de l'appelant : seule la copie de la référence est modifiée. En revanche t[0] = 99 modifie bien le tableau partagé.

Une récursion qui ne se rapproche pas du cas de base

Vérifie à chaque fois : « quel est le cas le plus simple ? » et « l'argument diminue-t-il à chaque appel ? ». Sinon, StackOverflowError.

📋 Aide-mémoire

  • static type nom(type p1, type p2) { … return valeur; } ; void si rien n'est renvoyé.
  • Depuis main, appelle des méthodes static ; chaque chemin d'une méthode non void finit par un return.
  • Surcharge : même nom, paramètres différents (le compilateur choisit).
  • Java passe toujours une copie : valeur pour un nombre, référence pour un tableau ou un objet.
  • Une variable static de classe garde sa valeur entre les appels ; les variables locales disparaissent.
  • Récursion : un cas de base + un appel sur un cas plus petit.