Point-virgule à la fin de la déclaration ‘if’

Aujourd’hui, après une demi-heure de recherche d’un bug, j’ai découvert qu’il était possible de mettre un point-virgule après une instruction if à la place du code, comme ceci:

if(a == b); // Do stuff 

Ce qui signifie fondamentalement que le produit sera fait qu’il soit égal ou non, et que l’énoncé if n’a aucun sens. Pourquoi Java ne me donne-t-il pas d’erreur? Y a-t-il une situation dans laquelle cela serait utile?

Pourquoi ça arrive?

Java Language Specification dit que:

La déclaration vide

Une déclaration vide ne fait rien.

 EmptyStatement: ; 

L’exécution d’une instruction vide se termine toujours normalement

Cela signifie essentiellement que vous voulez exécuter une instruction vide si un == b

 if(a == b); 

Que devrais tu faire:

Il existe deux solutions principales à ce problème:

  1. Vous pouvez éviter les problèmes avec une instruction vide en utilisant le formateur de code et les éléments environnants à l’intérieur if avec { et } . En faisant cela, votre déclaration vide sera beaucoup plus lisible.

     if(a == b){ ; } 
  2. Vous pouvez également vérifier les outils utilisés pour l’parsing du code statique, tels que:

    • Findbugs
    • Style checkstyle
    • Pmd

    Ils peuvent instantanément mettre en évidence des problèmes tels que celui-ci.

Je recommanderais de combiner les deux solutions.

Y a-t-il une situation dans laquelle cela serait utile?

Utile? Comme dans “rend votre code plus propre, plus clair, plus rapide, plus facile à maintenir”? Pas du tout. C’est très probablement un code médiocre .

Mais ce n’est pas nécessairement bénin . Une telle déclaration peut effectuer des actions et / ou modifier l’état dû à des méthodes entraînant des effets secondaires et, éventuellement, évaluer ces méthodes en raison du court-circuit des opérateurs .

 if( a() && b() ); 

Ici, a() ou b() peut faire quelque chose, et b() n’exécutera que si a() est vrai.

Pour ce qui est de la raison , je pense que la réponse est simplement qu’il serait pire de s’écarter d’un comportement défini et attendu (par exemple, des déclarations comme while(reader.read()); )

Écrire un code incorrect est toujours possible. Et pour rappel, ce serait un mauvais code dans presque tous les cas.

Un cas d’utilisation possible:

 if (a==b); else { // Do something } 

Pas bien, mais possible.

Pourtant, je pense que la spécification Java devrait interdire un vide if .

Si vous utilisez Eclipse, vous pouvez le faire pour vous avertir de ces déclarations:

Java-/> Comstackr-> Erreurs / Avertissements”></p>
</div>
</li><!-- #comment-## -->
<div class=

Si vous utilisez une instruction if , la première instruction après le if sera exécutée si la condition est vraie. Si vous avez un bloc après le if (avec des accolades), cela compte pour ce bloc entier. S’il n’y a pas de bloc, il ne compte que pour une seule déclaration. Un seul point-virgule est une instruction vide. Vous pouvez également écrire le code de votre exemple comme ceci:

 if(a==b) { ; } 

C’est un vieux vestige de l’époque où il y avait plus de sucre syntaxique pour différencier les expressions des déclarations.

Fondamentalement, la virgule a été utilisée comme séparateur d’élément de liste. Le point-virgule a donc été utilisé comme séparateur “liste d’instructions”. L’inconvénient est la gestion des éléments nuls dans les listes et des instructions null dans les blocs.

Dans une liste d’éléments, Java utilise le mot clé explicite null , mais une “instruction null” n’est qu’une ligne vide. Permettre l’existence d’une ligne vide est un vestige de la tradition héritée de C.

Pourquoi le faire? Surtout avec une instruction if quand vous savez qu’aucune instruction n’est en cours d’exécution: car certaines instructions ont des effets secondaires:

  int c; if ((c = in.read()) != -1); 

Oui, ce n’est pas le meilleur exemple, mais en gros, il est dit de lire un octet du stream et de ne rien faire. Peut être utile dans certains cas de figure, mais même si cet exemple n’est pas le meilleur, il illustre l’intention. Nous voulons ressentir les effets secondaires de l’expression sans exécuter accidentellement des instructions.

Je ne peux pas penser à une occasion où c’est utile. Il peut être utile pour des boucles comme

  while(do something); 

ou

  for(init; do something; something else); 

Si vous utilisez régulièrement le formatage de votre code dans votre IDE, ce type de bogue devient évident. Certains IDE le soulignent également comme un bug probable.

Je suis d’accord avec vous, il n’y a pas de but utile pour un humain. Je pense que c’est là parce que cela simplifie la définition de la langue. cela signifie que la chose qui vient après un if est la même que celle qui arrive après un while , par exemple.

Pourquoi? C’est parce que c’est plus facile pour les auteurs de compilateurs. Vous n’avez pas besoin de faire un cas particulier pour vérifier les points-virgules après if(cond) et a une utilisation supplémentaire de permettre

 if (cond && maybeFunc()) ;// Code here I want to ignore 

Même si c’est une idée terrible de permettre cela. Il est juste plus facile d’autoriser, puis d’append un cas pour vérifier cela.

Java permet un bloc vide n’importe où un bloc d’instruction est autorisé. Je suis sûr que faire de cette règle une règle générale pour tous les blocs simplifie le compilateur.

Je suis d’accord que c’est avant tout la cause des bugs qui sont spectaculairement difficiles à trouver. J’utilise toujours des accolades autour des blocs, même quand il n’y a qu’une seule instruction, mais Java vous permet de créer un bloc avec des accolades à tout moment. L’utilisation d’accolades ne peut donc pas vous sauver de ce destin. Par exemple, j’ai déjà perdu 4 heures à essayer de trouver quelque chose comme ceci:

 while (condition); { statement; statement; } 

Le point-virgule à la fin de la première ligne était une faute de frappe, rendant le bloc d’instruction de la boucle while vide. Parce que la syntaxe est valide, le programme compilé et exécuté correctement, mais pas comme je le voulais. C’était vraiment difficile à trouver.

Je peux penser à une situation où il est très agréable d’avoir des blocs vides, et c’est quelque chose comme ceci:

 if (condition1) { do_action_1(); } else if (condition2) { //nothing really to do in this case } else if (condition3) { do_action2(); } else { do_action3(); } 

Dans l’exemple ci-dessus, vous voulez pouvoir séparer différentes conditions. N’oubliez pas que ces conditions peuvent se chevaucher, il n’est donc pas toujours possible de modifier l’ordre. Si l’une des conditions n’a vraiment pas besoin de faire quelque chose, alors c’est bien que Java vous permette d’avoir un bloc vide. Sinon, le langage nécessiterait une forme de méthode “noop” à utiliser lorsque vous ne voulez vraiment rien faire.

Personnellement, je préférerais la déclaration explicite “noop” – mais ce n’est pas ainsi que Java est défini.

Juste un FYI sur la facilité d’utilisation et quelle différence cela fait ou peut faire s’il y a une déclaration comme ça

Considérez un morceau de code comme celui-ci.

 int a = 10; if ((a = 50) == 50); System.out.println("Value of a = " + a); 

Clairement, dans ce cas, l’instruction if modifie la sortie. Une telle déclaration peut donc faire la différence.

C’est une situation où cela pourrait être utile ou mieux dire avoir un impact sur le programme.

 if(a==b) println("a equals b"); 

Vous pouvez utiliser une instruction IF sans {} s’il n’y a qu’une seule ligne à exécuter. En utilisant if(a==b); vous dites que si elles sont égales, exécutez et videz l’instruction … Donc, elle ne fera rien, puis reviendra à votre boucle normale, en dehors du bloc IF.

Quelques définitions des jls l’expliquent (chapitre 14):

Les blocs sont des déclarations

Comme indiqué ici , un Block est un StatementWithoutTrailingSubstatement , qui à son tour est un StatementNoShortIf , qui est une Statement . Ainsi, chaque fois que cela est nécessaire, nous pouvons insérer un Block .

La clause if

Bien que ce soit aussi le cas pour for et- while boucles, j’utiliserai if -statements. Ces règles sont à peu près les mêmes. La description syntaxique des if-statements peut être trouvée ici .

 IfThenStatement: if ( Expression ) Statement IfThenElseStatement: if ( Expression ) StatementNoShortIf else Statement IfThenElseStatementNoShortIf: if ( Expression ) StatementNoShortIf else StatementNoShortIf 

Nous pouvons donc utiliser notre bloc ici.

Mais pourquoi ça marche avec? ?

; est défini comme EmptyStatement ( lien ), qui est également un StatementNoShortIf . Donc, dans les éléments de code conditionnels, comme if-statement et loops, nous pouvons remplacer un Block par un EmptyStatement , si un StatementNoShortIf ou un Statement est requirejs.

Donc if(Expression)EmptyStatement fonctionne.

Pourquoi cela ne donne-t-il pas une erreur?

Assez simple: java donne une erreur s’il trouve une syntaxe invalide. Mais if(Expression)EmptyStatement est une syntaxe parfaitement valide. Au lieu de cela, javac émet un avertissement s’il est lancé avec les parameters appropriés. La liste complète des avertissements pouvant être désactivés / activés répertorie le nom d’avertissement empty à cette fin. Donc, la compilation avec -Xlint:all ou -Xlint:empty générera un avertissement à ce sujet.

Votre IDE devrait également avoir une option pour activer ce type d’avertissement. Pour eclipse, voir la réponse de @ nullptr . Dans IntelliJ, vous pouvez appuyer sur Ctrl + Shift + A , entrer un empty body dans le champ de recherche et activer l’avertissement (marqué dans l’image)

IntelliJ active l'avertissement de corps vide

A quoi cela sert-il même?

Pour être honnête, il n’y a pas beaucoup d’utilité d’un sharepoint vue minimaliste. Il existe généralement un moyen d’obtenir des résultats sans commande «ne rien faire». C’est plutôt une question de préférences personnelles, que vous préfériez utiliser

 if( a() && b() ); 

ou

 if( a() ) b(); 

et même serait applicable à d’autres cas, dans lesquels le EmptyStatement est utilisé. Un point important à considérer sur ce sujet est la lisibilité du code. Il y a des occasions où le code devient plus lisible en utilisant le non-op. D’un autre côté, il y a des cas où le code devient beaucoup plus difficile à comprendre avec l’utilisation de EmptyStatement – l’exemple ci-dessus compte pour la dernière IMO.

Point-virgule à la fin de,
si (a == b); il suffit de terminer l’instruction en une seule ligne, ce qui signifie ignorer le résultat de la condition et continuer l’exécution à partir de la ligne suivante
Ce code est utile, d’autre part, introduisez parfois un bogue dans le programme, par exemple,

cas 1.

a = 5;
b = 3;
si (a == b);
prinf (“a et b sont égaux”);

cas 2.

a = 5;
b = 5;
si (a == b);
prinf (“a et b sont égaux”);
imprimerait la même sortie sur l’écran …

Je peux penser à un scénario où une instruction vide est requirejse (pas pour if condition mais pour while boucle).

Lorsqu’un programme veut simplement une confirmation explicite de l’utilisateur pour continuer. Cela peut être nécessaire lorsque le travail après la confirmation de l’utilisateur dépend de certaines autres choses et que l’utilisateur souhaite prendre le contrôle de la procédure à suivre.

  System.out.println("Enter Y to proceed. Waiting..."); System.out.println(""); while(!(new Scanner(System.in).next().equalsIgnoreCase("Y"))); System.out.println("Proceeding..."); // do the work here 

Tout en travaillant sur une tâche de programmation pour une classe où je travaille avec une grid de doodads N par N et en comparant les caractéristiques d’un doodad aléatoire à celles ci-dessus, dessous, gauche et droite, j’ai trouvé exceptions de limites potentielles. Mon objective était de minimiser le code et de ne pas imbriquer les instructions if.

 if (row == 0); else (method (grid[row][col], grid[row-1][col])); if (row == N-1); else (method (grid[row][col], grid[row+1][col])); if (col == 0); else (method (grid[row][col], grid[row][col-1])); if (col == N-1);
else (method (grid[row][col], grid[row][col+1]));

method(Doodad a, Doodad b) effectue des opérations entre a et b.

Vous pouvez également utiliser la gestion des exceptions pour éviter cette syntaxe, mais cela fonctionne et fonctionne bien pour mon application.