Point-virgule à la fin de l'if
aujourd'Hui, après une demi-heure de recherche pour un bug, j'ai découvert qu'il est possible de mettre un point-virgule après l'instruction if au lieu de code, comme ceci:
if(a == b);
// Do stuff
ce qui signifie essentiellement que le truc sera fait que a égale b ou non, et la déclaration de si n'a aucun sens. Pourquoi Java ne me donne-t-il pas une erreur? Est-il une situation où ce serait utile?
16 réponses
pourquoi ça arrive?
Java Language Specification says that:
L'Instruction 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 l'instruction vide si a = = b
if(a == b);
Que devez-vous faire:
il y a deux principales solutions à ce problème:
-
vous pouvez éviter les problèmes avec la déclaration vide en utilisant le Code formatter et tout ce qui l'entoure à l'intérieur de
if
avec{
et}
. En faisant cela, Votre déclaration vide sera beaucoup plus lisible.if(a == b){ ; }
-
Vous pouvez également vérifier outils utilisés pour l'analyse de codes statiques tels que:
ils peuvent instantanément mettre en évidence des problèmes tels que celui-ci.
je recommande de combiner les deux solution.
y a-t-il une situation dans laquelle cela serait utile?
utile? Comme dans "rend votre code plus propre, plus clair, plus rapide, plus maintenable"? Pas du tout. C'est très probablement code pauvre et confus .
mais ce n'est pas nécessairement Bénin . Une telle déclaration peut effectuer des actions et / ou modifier l'état en raison de méthodes qui causent des effets secondaires, et évaluer ceux-ci méthodes dues à court-circuitage des opérateurs .
if( a() && b() );
Ici, a()
ou b()
peut faire quelque chose, et b()
ne s'exécutera que si a()
est vrai.
quant à pourquoi , je pense que la réponse est simplement qu'il serait pire de s'écarter du comportement défini et attendu (par exemple des déclarations comme while(reader.read());
) que l'alternative des développeurs écrivant du mauvais code.
Écrire un mauvais code est toujours possible. Et juste pour le répéter, ce serait un mauvais code dans presque tous les cas.
un cas d'utilisation possible:
if (a==b);
else {
// Do something
}
pas bon, mais possible.
pourtant, je pense que la spécification Java devrait rejeter un vide if
.
si vous utilisez Eclipse, vous pouvez le faire vous avertir à propos de ces déclarations:
si vous utilisez une instruction if
, la première instruction après la if
sera exécutée si la condition est vraie. Si vous avez un bloc après le if
(avec attelles bouclées), il compte pour tout le bloc. Si il n'y a pas de bloc il compte pour une seule instruction. Un seul point-virgule est une instruction vide. Vous pouvez aussi écrire le code de votre exemple comme ceci:
if(a==b) {
;
}
c'est un vieux résidu de l'époque où il y avait plus de sucre syntaxique pour différencier les expressions des affirmations.
essentiellement, la virgule a été utilisée comme séparateur d'éléments de liste, de sorte que le point-virgule a été utilisé comme séparateur de" liste d'énoncés". L'inconvénient est dans le traitement des éléments nuls dans les listes, et les déclarations nulles dans les blocs.
dans une liste D'articles, Java utilise le mot-clé explicite null
, mais une "déclaration nulle" est juste un ligne vide. Permettre l'existence d'une ligne vide est un prolongement de la tradition héritée de C.
Pourquoi faire? En particulier avec une déclaration if
quand vous savez qu'Aucune déclaration n'est exécutée: parce que certains si les déclarations ont des effets secondaires:
int c;
if ((c = in.read()) != -1);
Oui, ce n'est pas le meilleur exemple, mais fondamentalement il dit lire un octet du ruisseau et ne rien faire. Peut être utile dans certains cas particuliers, mais même si cet exemple n'est pas le mieux, il illustre l'intention. Nous voulons ressentir les effets secondaires de l'expression sans exécuter accidentellement des déclarations.
je ne peux pas penser à une occasion où il est utile. Il peut être utile pour les boucles comme
while(do something);
ou
for(init; do something; something else);
si vous utilisez votre formatage de code dans votre IDE régulièrement ces sortes de bogues deviennent évidents. Certains IDEs soulignent également qu'il s'agit d'un bogue probable.
je serai d'accord avec vous il n'y a aucune utilité pour l'homme. Je soupçonne qu'il est là parce qu'il simplifie la définition de la langue; il signifie que la chose qui vient après un if
est e même que la chose qui vient après un while
, par exemple.
pourquoi? C'est parce que c'est plus facile pour les rédacteurs de compilateurs. Vous ne devez pas faire un cas spécial pour vérifier les points-virgule après if(cond)
et a une utilisation supplémentaire d'autoriser
if (cond && maybeFunc())
;// Code here I want to ignore
même si c'est une très mauvaise idée de permettre cela. Il est juste plus facile d'autoriser et puis d'ajouter un cas pour vérifier cela.
Java permet un bloc vide n'importe où un bloc de déclaration est autorisé. Je suis sûr que faire de cela une règle générale pour tous les blocs simplifie le compilateur.
je suis d'accord que c'est principalement la cause des bogues qui sont extraordinairement difficiles à trouver. J'utilise toujours des bagues autour des blocs, même lorsqu'il n'y a qu'une seule déclaration, mais Java vous permet de faire un bloc avec des bagues à tout moment, donc utiliser des bagues ne peut pas vous sauver de ce destin. Par exemple, j'ai perdu une fois 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 accidentellement vide le bloc d'instructions pour la boucle while. Parce que la syntaxe est valide, le programme a été compilé et s'est bien déroulé, mais pas comme je le voulais. C'était vraiment difficile à trouver.
je ne peux penser à une situation où il est très gentil que vous êtes autorisé à 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 diverses conditions. Rappelez-vous, ces conditions peuvent être superposées, de sorte qu'il n'est pas toujours possible de réorganiser l'ordre. Si l'une des conditions n'a pas vraiment besoin de rien faire, alors c'est bien que Java permet d'avoir un bloc vide. Sinon, le langage aurait besoin d'une certaine forme de méthode "noop" à utiliser quand vous ne voulez vraiment pas que quelque chose soit fait.
personnellement, je préférerais l'énoncé explicite "noop" -- mais ce N'est pas ainsi que Java est défini.
Juste pour info au sujet de la convivialité et de la la différence qu'il fait ou peut faire si il ya une telle déclaration
considérez un morceau de code comme le suivant.
int a = 10;
if ((a = 50) == 50);
System.out.println("Value of a = " + a);
clairement dans ce cas, l'énoncé if
change la sortie. Une telle déclaration peut donc faire une différence.
C'est une situation où cela pourrait être utile, ou pour 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, donc en utilisant if(a==b);
vous dites si elles sont égales, exécutez et videz l'instruction... Donc, il ne fera rien, et ensuite revenir à votre boucle normale, en dehors du bloc si.
quelques définitions du jls expliquent ceci (chapitre 14):
Blocs sont des Énoncés
comme indiqué ici , un Block
est un StatementWithoutTrailingSubstatement
, qui à son tour est un StatementNoShortIf
, qui est un Statement
. Ainsi, lorsque l'un quelconque de ces éléments est requis, nous pouvons insérer un Block
.
si la clause
bien que ce soit aussi le cas pour for
et while
- loops, je vais utiliser if
- statements. Ces règles sont à peu près les mêmes. La description syntaxique de if-statements
peut être trouvée ici .
IfThenStatement:
if ( Expression ) Statement
IfThenElseStatement:
if ( Expression ) StatementNoShortIf else Statement
IfThenElseStatementNoShortIf:
if ( Expression ) StatementNoShortIf else StatementNoShortIf
donc nous pouvons utiliser notre bloc ici.
mais pourquoi cela fonctionne-t-il avec ; ?
;
est défini comme le EmptyStatement
( link ), qui est aussi un StatementNoShortIf
. Ainsi en morceaux conditionnels de code, comme if-statement
et les boucles, nous pouvons remplacer un Block
par un EmptyStatement
, si un StatementNoShortIf
ou Statement
est nécessaire.
donc if(Expression)EmptyStatement
travaux.
pourquoi ça ne donne pas une erreur?
assez simple: java donne une erreur si elle trouve une syntaxe invalide. Mais if(Expression)EmptyStatement
est une syntaxe parfaitement valide. Au lieu de cela javac
donne un avertissement si lancé avec les paramètres appropriés. Le complet liste des avertissements qui peuvent être désactivés/activés liste l'avertissement-nom empty
à cette fin. Ainsi la compilation avec -Xlint:all
ou -Xlint:empty
générera un avertissement à ce sujet.
votre IDE devrait aussi 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 empty body
dans le champ de recherche et activer l'avertissement (marqué dans l'image)
à quoi sert-il?
pour être honnête, il n'y a pas beaucoup d'utilisation d'un point de vue minimaliste. Il y a généralement un moyen de faire les choses sans un ordre de "ne rien faire". C'est plutôt une question de préférences personnelles, si vous utilisez plutôt
if( a() && b() );
ou
if( a() ) b();
et même s'appliquer à 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 no-op. D'un autre côté, il y a des cas où le code devient beaucoup plus difficile à comprendre avec l'utilisation du EmptyStatement
- l'exemple ci-dessus compterait pour L'IMO plus tard.
Point-Virgule à la fin de
if (a==b); simplement 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, parfois, introduire un bug 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");
imprimez le même résultat sur l'écran...
je peux penser à un scénario où un énoncé vide est requis (pas pour la condition if
mais pour la boucle while
).
quand un programme veut juste une confirmation explicite de l'utilisateur pour procéder. Cela peut être nécessaire lorsque le travail après la confirmation de l'utilisateur dépend d'autres choses et de l'utilisateur veut prendre le contrôle de quand à poursuivre.
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
en travaillant sur une tâche de programmation pour class où je travaille avec une grille n by N de doodads et en comparant les caractéristiques d'un doodad aléatoire à celles ci-dessus, en bas, à gauche et à droite, j'ai trouvé une bonne utilisation de ceci pour prévenir des déclarations emboîtées et des exceptions de limite potentielles. Mon but était de minimiser le code et d'éviter de faire des déclarations 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);<br>
else (method (grid[row][col], grid[row][col+1]));
où method(Doodad a, Doodad b)
fait une certaine opération entre a et B.
Alternativement, vous pouvez utiliser la manipulation d'exception pour éviter cette syntaxe, mais elle fonctionne et fonctionne bien pour mon application.