[Java] Utilisation de final dans la déclaration de variable locale

Est-ce que final est nécessaire pour déclarer les variables locales?

Je n'utilise essentiellement pas final dans mes propres fonctions. Je pense que la raison est simplement "Je l'ai écrit pour que vous puissiez le voir". Par exemple, il a la forme suivante.

public static int f(int x) {
  int y = g(x);
  int z = h(y);
  return z;
}

Quand vous regardez cela, il va de soi que y et z (et x) ne sont pas réaffectés. Et comme la fonction que je définis est généralement de quelques lignes comme celle-ci, je pense que l'ajout de final au moment de la déclaration est redondant, alors j'essaye de ne pas l'ajouter.

Cependant, je pense que c'est normal d'en avoir un autre. Par exemple, si les paramètres IDE sont définis pour ajouter automatiquement la finale, au moins cela n'affectera pas le nombre de types, et je pense qu'il s'habituera bientôt à l'apparence. Bref, dans les cas ci-dessus, nous ne sommes pas si particuliers à ce sujet.

Situations qui utilisent final

Eh bien, si vous n'utilisez pas du tout final, ce n'est pas le cas, et dans certains cas, il peut être utilisé. Ci-dessous, je présenterai un cas où j'utilise personnellement final.

1. Déclaration dans une longue fonction

Puisque la fonction ci-dessus a été définie par moi-même, cela n'a pris que quelques lignes, mais lors de sa modification dans les affaires réelles, il est possible de déclarer des variables dans une fonction très longue (centaines de lignes, mille lignes, etc.). Dans de telles fonctions, il n'est pas rare qu'il y ait des dizaines ou des centaines de lignes entre la déclaration de variable et l'endroit où la variable est utilisée. À ce moment-là, si final n'est pas joint au moment de la déclaration, il est nécessaire de lire toutes les lignes intermédiaires et de saisir la dernière valeur.

numéro de ligne
100      public static int longLongFunc() {
101        String foo = "foo";

~~ Omis ~~

           //Vous devez lire les 400 lignes entre les deux pour connaître la valeur de foo à ce stade.
500        String bar = hoge(foo);

・ ・ ・

Sinon, la portée continuera après l'utilisation de la variable, de sorte que la valeur ne peut plus changer dans les lignes en dessous.

           //Il peut être réutilisé comme ça(Qu'est-ce que l'initialisation ...)¡
700        foo = null; //Initialisation
701        foo = fuga();

・ ・ ・

Bien sûr, cela peut être une histoire qui peut être évitée par la révision du code, mais dans le monde réel, il n'est pas rare que les entreprises n'aient pas une telle culture.

Les cas ci-dessus peuvent être traités en ajoutant final lors de la déclaration.

numéro de ligne
100      public static int longLongFunc() {
101        final String foo = "foo";

~~ Omis ~~

           //La valeur de foo n'a pas changé depuis sa déclaration("foo"Tel quel)Par conséquent, il n'est pas nécessaire de saisir le traitement intermédiaire.
500        String bar = hoge(foo);

~~ Omis ~~

           //Ne peut pas être réutilisé dans la ligne ci-dessous car cela entraînera une erreur de compilation
700        foo = null; //Erreur de compilation


・ ・ ・

2. Lors de la définition d'une valeur en fonction des conditions

(Post-scriptum du 19/10/1 / correction) @Kilisame l'a souligné dans les commentaires, et j'ai découvert mon gros malentendu, alors je fais une correction majeure. Les variables locales Java, indépendamment de la présence ou de l'absence de final, provoqueront une erreur de compilation si la valeur initiale n'est pas affectée uniquement par la déclaration, mais dans le cas de la déclaration uniquement, la valeur initiale implicite est affectée comme le champ. Je l'ai mal compris. Merci d'avoir souligné, @Kilisame.


Le branchement conditionnel utilise également souvent final. Par exemple, considérons le cas suivant.
String hoge = "";
if (isFoo) {
  hoge = "foo";
} else if (isBar) {
  hoge = "bar";
}

Si vous ne voulez tout simplement pas réattribuer, vous pouvez également utiliser l'opérateur conditionnel (opérateur ternaire) pour écrire:

String hoge = isFoo ? "foo" : isBar ? "bar" : "";

Ce n'est pas impossible d'écrire, mais il est certainement difficile de voir si else if est mélangé, pas seulement if-else. Fondamentalement, il vaut mieux éviter l'imbrication d'opérateurs conditionnels. Dans un tel cas, vous pouvez également écrire comme suit.

// 19/10/1 commentaire pour correction(Voir les notes supplémentaires)
// final String hoge; //Déclaration uniquement

String hoge; //Déclaration uniquement
//Remplacez une valeur en fonction de la condition
if (isFoo) {
  hoge = "foo";
} else if (isBar) {
  hoge = "bar";
} else {
  hoge = "";
}

Puisque ~~ final est "une valeur qui ne peut être attribuée qu'une seule fois", le moment de la déclaration et de l'affectation lui-même peut être différent. Au lieu de cela, vous obtiendrez une erreur de compilation si vous ne définissez pas de valeur quelque part avant qu'elle ne soit hors de portée. L'avantage de l'écriture ci-dessus est que vous pouvez empêcher la surveillance des cas où aucune valeur n'est définie. Par exemple, l'exemple suivant entraînera une erreur de compilation. ~~

(Post-scriptum du 19/10/1 / correction) Même s'il n'y a pas de final, une erreur de compilation se produira si la valeur initiale n'est pas affectée uniquement dans la déclaration.

// 19/10/1 commentaire pour correction
// final String hoge;

String hoge;
if (isFoo) {
  hoge = "foo";
} else if (isBar) {
  String fuga = getFuga();
  if (!fuga.isEmpty()) {
    hoge = fuga;
  } //Si c'est faux, la valeur ne sera pas définie, ce qui entraînera une erreur de compilation.
} else {
  hoge = "";
}

Afin de réussir la compilation, il est nécessaire de couvrir tous les cas comme suit.

// 19/10/1 commentaire pour correction
// final String hoge;

String hoge;
if (isFoo) {
  hoge = "foo";
} else if (isBar) {
  String fuga = getFuga();
  if (!fuga.isEmpty()) {
    hoge = fuga;
  } else {
    hoge = "bar";
  }
} else {
  hoge = "";
}

~~ Pour compléter un peu plus, supprimez la finale de l'exemple ci-dessus qui provoque une erreur de compilation et remplacez-la par la valeur initiale. ~~

(Post-scriptum du 19/10/1 / correction) Puisque final est supprimé, seule la valeur initiale est remplacée.

String hoge = "";
if (isFoo) {
  hoge = "foo";
} else if (isBar) {
  String fuga = getFuga();
  if (!fuga.isEmpty()) {
    hoge = fuga;
  } //Quand c'est faux, hoge est""tel quel.
}

Dans ce cas, la compilation elle-même passera. Cependant, cela peut être dû au fait que vous avez oublié d'écrire le cas où fuga.isEmpty () est true (bien sûr, cela peut être comme prévu).

String hoge = "";
if (isFoo) {
  hoge = "foo";
} else if (isBar) {
  String fuga = getFuga();
  if (!fuga.isEmpty()) {
    hoge = fuga;
  } else {
    hoge = "bar"; //Peut-être que j'avais l'intention d'écrire comme ça
  }
}

Ce type de bogue est également un bogue courant dans la pratique. Les gens sont des créatures qui font des erreurs. Donc, de cette façon, il est plus sûr et plus sûr d'écrire de telle manière qu'une erreur de compilation se produise si vous faites une erreur, plutôt que d'écrire de telle manière que la compilation passera dans les deux cas d'erreurs et non. ~~ Si vous oubliez d'écrire l'exemple ci-dessus, vous pouvez éviter les bogues inattendus en ajoutant final. ~~

(Post-scriptum du 19/10/1 / correction) La directive elle-même, "Si vous faites une erreur, vous devriez obtenir une erreur de compilation" ne change pas, mais l'exemple ci-dessus est inapproprié car il ne concerne pas la présence ou l'absence de final. En ce qui concerne les mérites de l'ajout final dans de tels cas, @Kilisame a souligné, illustré et expliqué dans la section des commentaires, veuillez donc vous y référer.
En plus de l'exemple ci-dessus, il est également bon de créer la fonction suivante et de l'appeler.

//Ring hoge si transformé en fonction= getHoge();Peut être écrit
public static String getHoge() {
  if (isFoo) {
    return "foo";
  } 
  
  if (isBar) {
    String fuga = getFuga();
    if (!fuga.isEmpty()) {
      return fuga;
    } else {
      return "bar";
    }
  }
  return "";
}

J'aimerais que vous réfléchissiez à l'opportunité d'en faire une fonction au cas par cas.

Résumé

Actuellement, je n'ajoute pas final à toutes les variables locales, mais j'ai l'intention d'écrire avec l'intention que "final puisse être ajouté à toutes les variables locales". Plutôt que d'ajouter ou non final, si vous êtes bien conscient de l'arrière-plan et du but de l'ajout de final, tels que «éviter les bogues inattendus» et «réparer facilement», il ne peut pas tourner dans la mauvaise direction. Je suis en train de penser.

Ou s'il s'agit de développement d'équipe, je pense que la stratégie de forcer le final dans la norme de codage et de n'assurer que la qualité minimale sans que le programmeur s'en rende compte est aussi une fourmi.

Dans cet article, je voulais simplement présenter le cas selon lequel "il est plus pratique d'utiliser final dans de tels cas" au lieu de "utiliser ou non final", afin que vous ou votre équipe décidez quoi faire. J'espère que vous pouvez y réfléchir.

Merci d'avoir lu pour moi jusqu'à la fin. Si vous avez des questions ou des lacunes, veuillez nous contacter dans la section commentaires ou Twitter.

Recommended Posts

[Java] Utilisation de final dans la déclaration de variable locale
déclaration de variable java
À propos de var utilisé en Java (type de variable locale)
Utiliser OpenCV avec Java
Utiliser PreparedStatement en Java
Utilisation correcte de la classe abstraite et de l'interface en Java
À propos des instructions de déclaration de variable Java
Implémentation Java de tri-tree
Déclaration, initialisation et types de variables Java
[Java] N'utilisez pas "+" dans append!
Utilisez des clés composites dans Java Maps.
Comment écrire une déclaration de variable Java
Liste des membres ajoutés dans Java 9
Comment utiliser les classes en Java?
Liste des types ajoutés dans Java 9
Implémentation d'une fonction similaire en Java
Utilisez-vous Stream en Java?
[Java8] Utilisation appropriée de Compareable et Comparator du point de vue du tri des employés
Implémentation de DBlayer en Java (RDB, MySQL)
Obtenez le résultat de POST en Java
Prise en charge multilingue de Java Comment utiliser les paramètres régionaux
Utilisez OpenCV_Contrib (ArUco) avec Java! (Partie 2-Programmation)
Créer des données binaires de longueur variable en Java
Différence entre final et immuable en Java
Utiliser un bloc d'initialisation statique pour initialiser la liste / l'ensemble de champs statiques en Java
[Java] Utiliser la technologie cryptographique avec les bibliothèques standard
Utilisez "Rhino" qui exécute JavaScript en Java
Qu'est-ce qui n'était pas une utilisation équitable du détournement d'API Java sur Android?
[Java] [Maven3] Résumé de l'utilisation de Maven3
L'histoire de l'écriture de Java dans Emacs
Rôle de JSP dans les applications Web [Java]
Discrimination d'énum dans Java 7 et supérieur
[Java] Pourquoi utiliser StringUtils.isEmpty () au lieu de String.isEmpty ()
Utilisez jenv pour activer plusieurs versions de Java
L'histoire de la comparaison de chaînes de bas niveau en Java
[Java] Gestion des Java Beans dans la chaîne de méthodes
L'histoire de la fabrication d'un Othello ordinaire à Java
À propos de l'idée des classes anonymes en Java
[Android / Java] Exploitez une base de données locale dans la salle
L'histoire de l'apprentissage de Java dans la première programmation
[Java] utilise facultatif au lieu de if (hoge! = Null) {...}
Ressentez le passage du temps même à Java
Modifier dynamiquement les champs finaux statiques privés en Java
Un examen rapide de Java appris en classe
Comment utiliser JQuery dans Rails 6 js.erb
[JAVA] [Spring] [MyBatis] Utiliser IN () avec SQL Builder
Ce qui m'a toujours intéressé dans Java Final
Nom de méthode de la chaîne de méthodes dans Java Builder + α
[Java] Différence entre "variable finale" et "objet immuable"
Importer des fichiers de la même hiérarchie en Java
Moment d'initialisation de la variable membre avec la valeur finale
Partition en Java
Janken à Java
Portée de la variable Java (portée)
Portée de la variable Java
[Java] [Maven] Modèle de pom.xml pour enregistrer le fichier jar tiers dans le référentiel local