Passage des paramètres et comparaison d'objets

Passage des paramètres et comparaison d’objets #

Dans ce chapitre, nous allons expliquer la particularité du passage des paramètres par valeur pour comprendre pourquoi il faut être vigilant lorsque nous prêtons nos objets à des API tierces. Nous reviendrons également sur les dangers de la comparaison d’objets qui est une source d’erreurs courantes en Java.

Passage des paramètres par valeur #

En Java, le passage des paramètres se fait par valeur et non par référence : la valeur de l’argument est copiée. S’il s’agit d’un type primitif, une copie est réalisée et il est impossible de modifier sa référence.

1
2
3
void test(int i) {
    i = i + 1;
}

Dans la méthode test, i a été copié. La modification n’a aucun impact pour l’appelant:

1
2
3
int value = 10;
test(value);
System.out.println(value); // ==> affiche 10

Pour les objets, il en est tout autre : c’est la référence qui est copiée. Prenons des objets mutables que nous connaissons:

void test(final StringBuilder str, final List<Integer> is) {
    str.append("hacked!");
    is.add(42);
}

...

StringBuilder dontTouchPlease = new StringBuilder();
List<Integer> emptyList = new ArrayList<>();
test(dontTouchPlease, emptyList);
// dontTouchPlease ==> "hacked!"
// emptyList ==> [42]

Dans la méthode test, str est une nouvelle référence copiée MAIS qui pointe sur le même objet en mémoire. Pareil pour is. Si les objets sont mutables, il est donc possible de les modifier, même si les références sont finales.

De la même façon, l’opérateur d’affectation ne copie pas un objet, il copie sa référence:

1
2
3
4
5
List<Integer> is1 = new ArrayList<>();
List<Integer> is2 = is1;
is2.add(42);
// is1 ==> [42]
// is2 ==> [42]

Il s’agit d’un autre avantage de travailler avec des objets immutables. Une méthode qui prend un String ne peut pas faire de dégâts puisque l’objet ne peut pas être modifié.

Conseil

Ne faites confiance à personne ! Soyez conservateur avec vos références. Si une API vous demande un objet mutable dont vous souhaitez garder la propriété, copiez-le ou transmettez une vue immutable de l’objet. Si votre API doit retourner un objet mutable dont vous souhaitez également garder la propriété, faites de même.

Ne faites confiance à personne avec des API tierces:

1
2
3
4
5
6
// Collections.unmodifiableCollection retourne une vue immubable sans réaliser de copie 
giveMeYourList( Collections.unmodifiableCollection(dontTouchPlease) );

// copie de la liste
giveMeYourList( List.copyOf(dontTouchPlease) );
giveMeYourList( new ArrayList<>(dontTouchPlease) );

Pareil pour vos API. L’objet de a référence clients vous appartient.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class ClientDatabase {

    private List<String> clients = new ArrayList<>();

    public void addClient(String name) {
        clients.add(name);
    }

    public List<String> allClients() {
        // return this.clients; JAMAIS !
        return List.copyOf( this.clients ); // par exemple
    }
}

Conseil

Notez qu’il est possible de déclarer un argument final. Il s’agit même d’une bonne pratique.

void test(final int i) {
    i = i + 1; // ne compile plus
}

Nombre arbitraire d’arguments #

Une méthode peut comporter un nombre arbitraire d’arguments (entre 0 et une infinité). L’argument est considéré comme un tableau statique.

1
2
3
4
5
6
7
8
public class ClientDatabase {
    ...
    public void addClient(String... names) {
        for (String name: names) {
            clients.add(name);
        }
    }
    ...

Utilisations possibles:

1
2
3
4
5
ClientDatabase cd = new ClientDatabase();

cd.addClient("Joel", "Kevin", "Stéphane");
cd.addClient("Marc");
cd.addClient();

Comparaison #

Un piège fréquent est de comparer si deux objets sont égaux en utilisant l’opérateur ==. Comme nous l’avons déjà vu, cet opérateur compare les références et non la structure d’un objet. Il s’agit d’une source de bugs récurrents comme le montre cet exemple sur des chaînes de caractères:

"HELLO" == "hello".toUpperCase(); // ==> false
"HELLO".equals( "hello".toUpperCase() ); // ==> true











comments powered by Disqus