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?
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);
Il existe deux solutions principales à ce problème:
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){ ; }
Vous pouvez également vérifier les outils utilisés pour l’parsing du code statique, tels que:
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:
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):
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
.
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.
;
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.
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)
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]));
où 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.