34 votes

Pourquoi les initialisations explicites de la valeur par défaut sont-elles mauvaises?

J'ai exécuté checkstyle sur mon code et je suis tombé sur la règle ExplicitInitializationCheck. Pour l'instant, je ne sais pas pourquoi c'est une mauvaise chose.

La règle dit :

Vérifie si une classe ou un membre d'objet est explicitement initialisé à la valeur par défaut pour son type (null pour les références d'objet, zéro pour les types numériques et char et faux pour les booléens.

Raisonnement : chaque variable d'instance est initialisée deux fois, à la même valeur. Java initialise chaque variable d'instance à sa valeur par défaut (0 ou null) avant d'effectuer toute initialisation spécifiée dans le code. Donc, dans ce cas, x est initialisé à 0 deux fois, et bar est initialisée à null deux fois. Donc il y a une légère inefficacité. Ce style de codage est un vestige du codage de style C/C++, et il montre que le développeur n'est pas vraiment sûr que Java initialise vraiment les variables d'instance aux valeurs par défaut.

http://checkstyle.sourceforge.net/apidocs/com/puppycrawl/tools/checkstyle/checks/coding/ExplicitInitializationCheck.html

Une initialisation explicite, même si c'est la valeur par défaut, ne rend-elle pas le code plus lisible ? Est-il possible que les valeurs par défaut changent avec les versions JDK, ou les fournisseurs JVM ? De plus, n'est-ce pas quelque chose que HotSpot ou même le compilateur corrigerait également ?

12voto

Bohemian Points 134107

L'attribution de valeurs par défaut est un code redondant et relève du groupe de problèmes de style "encombrement de code".

Les valeurs par défaut pour les types sont définies dans la spécification du langage - elles ne vont pas changer, il est donc sûr de s'y fier.

De plus, vous n'apportez aucune clarté en attribuant des valeurs par défaut, car elles sont assez évidentes par défaut : zéro pour les primitives, null pour les objets.

9voto

bayou.io Points 3680

Je pense que c'est aussi mauvais, après avoir rencontré quelques bugs de concurrence.

Les écritures initiales par défaut se produisent avant tout le reste, il est donc plus simple de les analyser.

Cependant, une initialisation explicite, généralement dans le constructeur, est une écriture sur laquelle vous devez raisonner par rapport à d'autres lectures/écritures dans un environnement concurrentiel. C'est un travail supplémentaire qu'il vaut mieux éviter.

Si la variable d'instance est volatile, la raison d'éviter une écriture supplémentaire est plus forte, car une écriture supplémentaire volatile n'est pas bon marché et a plus d'impact sur la sémantique de la concurrence.

Dans cet exemple,

class Foo
    int i; // w0: écriture par défaut à 0

    int get()
        i=42;     // w2
        return i; // r2

get() retournera toujours 42. w0 se produit avant w2, il est donc toujours masqué, r2 ne verra pas w0.

Cependant, si nous ajoutons une initialisation explicite

class Foo

             // w0: écriture par défaut à 0
    int i=0; // w1: écriture explicite

    int get()
        i=42;     // w2
        return i; // i2

si l'instance est partagée par une publication non sécurisée, i2 pourrait voir w1, c'est-à-dire que get() pourrait retourner 0. Cela est dû au fait que w1 ne se produit pas avant w2.


P.S. Le fait de mettre à zéro n'est pas un problème trivial. Devrions-nous d'abord mettre à zéro une grosse partie de la mémoire, puis allouer des objets sur la partie mise à zéro? Ou devrions-nous d'abord allouer un objet (avec des valeurs de RAM aléatoires), puis mettre à zéro la région dans l'objet? Il n'y a pas de réponse facile.

4voto

Jonathan Drapeau Points 2156

La seule fois où j'ai vu l'attribution d'une valeur par défaut causer un problème, c'est avec l'héritage.

Prenons cet exemple :

public interface PanelInterface {

}

public class MyPanel extends JPanel implements PanelInterface {

}

public abstract class AClass {
  private PanelInterface panel;
  public AClass() {
    panel = createPanel();
  }

  protected abstract PanelInterface createPanel();
}

public class ChildAClass extends AClass {
  MyPanel myPanel = null;
  @Override
  protected PanelInterface createPanel() {
    myPanel = new MyPanel();
    return myPanel;
  }
}

La ligne MyPanel myPanel = null; va être appelée après que createPanel() soit appelée depuis le constructeur de AClass lors de la création d'une nouvelle instance de ChildAClass. L'attribution explicite d'une valeur par défaut va entraîner la variable myPanel à devenir null.

Sans l'assignation explicite, la valeur de myPanel restera telle que souhaitée.

Personnellement, je ne pense pas que ce soit du code superflu, mais les problèmes qu'il peut créer pourraient être suffisants pour ne pas le faire du tout.

2voto

Thomas Points 3776

Je pense que la vérification ExplicitInitialization peut être désactivée en toute sécurité. Indiquer explicitement la valeur à laquelle quelque chose est initialisé est une bonne chose. Cela aide à la lisibilité, et peut même aider certains lecteurs moins habiles à comprendre votre code. Ce sont parfois la majorité des personnes lisant votre code dans la vraie vie.

De plus, il n'y a pratiquement aucun gain de performance.

Que ce soit encombré ou non dépend de qui regarde - personnellement, je ne le pense pas. Mais si vous décidez d'appliquer cette règle, assurez-vous de l'appliquer de manière cohérente dans tout le code de votre application.

-1voto

fastcodejava Points 22174

Je pense que c'est mauvais parce que c'est

encombrement de code. Le gain de performance sur cela n'est pas significatif.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X