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 au lieu de code, comme ceci:
if(a == b);
// Do stuff
Ce qui signifie essentiellement que le travail sera fait que a
soit égal à b
ou non, et l'instruction if
n'a aucun intérêt. Pourquoi Java ne me donne-t-il pas une erreur? Y a-t-il une situation dans laquelle cela serait utile?
Java Language Specification dit que:
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 souhaitez exécuter une instruction vide si a == 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 de 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'analyse de 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 à entretenir"? Pas du tout. C'est très probablement un code pauvre et déroutant .
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 provoquent des effets secondaires, et éventuellement évaluer ces méthodes en raison de 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 d'un comportement défini et attendu (par exemple, des instructions comme while(reader.read());
) que l'alternative de développeurs écrivant du mauvais code.
Écrire un mauvais code est toujours possible. Et juste pour réitérer, ce serait du 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 interdire un if
vide.
Si vous utilisez Eclipse, vous pouvez le faire vous avertir de ces déclarations:
Si vous utilisez une instruction if
, la première instruction après if
sera exécutée si la condition est vraie. Si vous avez un bloc après le if
(avec des accolades), il compte pour ce bloc entier. S'il n'y a pas de bloc, il ne compte que pour une seule instruction. 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, donc le point-virgule a été utilisé comme séparateur de "liste d'instructions". L'inconvénient réside dans 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 "déclaration null" n'est qu'une ligne vide. Permettre l'existence d'une ligne vide est un résidu de tradition héritée de C.
Pourquoi le faire? Surtout avec une instruction if
lorsque vous savez qu'aucune instruction n'est en cours d'exécution: Parce que certaines instructions if ont des effets secondaires:
int c;
if ((c = in.read()) != -1);
Oui, ce n'est pas le meilleur exemple, mais en gros, il dit lire un octet du flux et ne rien faire. Peut être utile dans certains cas d'angle, 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ù cela soit 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 la mise en forme de votre code dans votre IDE régulièrement, ce type de bogues devient évident. Certains IDE le soulignent également comme un bogue probable.
Je suis d'accord avec vous qu'il n'y a aucun but utile à cela pour un humain. Je soupçonne que c'est là parce que cela simplifie la définition du langage; cela signifie que la chose qui vient après un if
est e identique à 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 n'avez pas besoin de créer un cas spécial pour vérifier les points-virgules après if(cond)
et vous pouvez également autoriser
if (cond && maybeFunc())
;// Code here I want to ignore
Même si c'est en fait une terrible idée de permettre cela. Il est simplement plus facile d'autoriser puis d'ajouter un cas pour vérifier cela.
Juste un info sur la convivialité 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 le suivant.
int a = 10;
if ((a = 50) == 50);
System.out.println("Value of a = " + a);
De toute évidence, dans ce cas, l'instruction if
modifie la sortie. Une telle déclaration peut donc faire la différence.
Il s'agit d'une situation où cela pourrait être utile ou mieux pour dire avoir un impact sur le programme.
Java autorise un bloc vide n'importe où un bloc d'instructions est autorisé. Je suis sûr que cela en fait une règle générale pour tous les blocs simplifie le compilateur.
Je suis d'accord que c'est principalement la cause de bugs qui sont spectaculairement difficiles à trouver. J'utilise toujours des accolades autour des blocs, même lorsqu'il n'y a qu'une seule instruction, mais Java vous permet de créer un bloc avec des accolades à tout moment, donc l'utilisation d'accolades ne peut pas vous sauver de ce sort. Pour par exemple, j'ai une fois perdu 4 heures à essayer de trouver quelque chose comme ça:
while (condition);
{
statement;
statement;
}
Le point-virgule à la fin de la première ligne était une faute de frappe, ce qui rendait accidentellement le bloc d'instructions pour la boucle while vide. 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 peux penser à une situation où c'est très bien 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 souhaitez pouvoir séparer différentes conditions. N'oubliez pas que ces conditions peuvent se chevaucher, il n'est donc pas toujours possible de réorganiser la commande. Si l'une des conditions n'a vraiment besoin de rien, alors c'est bien que Java vous permet d'avoir un bloc vide. Sinon, le langage aurait besoin d'une forme de méthode "noop" pour 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.
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 ... ne fera rien, puis reviendra à votre boucle normale, en dehors du bloc IF.
Quelques définitions des jls expliquent cela (chapitre 14):
Comme indiqué ici , un Block
est un StatementWithoutTrailingSubstatement
, qui à son tour est un StatementNoShortIf
, qui est un Statement
. Ainsi, lorsque cela est nécessaire, nous pouvons insérer un Block
.
Bien que ce soit également le cas pour les boucles for
et while
-, j'utiliserai les instructions if
-. 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
Nous pouvons donc utiliser notre bloc ici.
;
Est défini comme EmptyStatement
( link ), qui est aussi un StatementNoShortIf
. Ainsi, dans les morceaux de code conditionnels, comme if-statement
Et les boucles, nous pouvons remplacer un Block
par un EmptyStatement
, si un StatementNoShortIf
ou Statement
est requis.
Ainsi if(Expression)EmptyStatement
fonctionne.
Assez simple: Java donne une erreur s'il trouve une syntaxe non valide. Mais if(Expression)EmptyStatement
est une syntaxe parfaitement valide. Au lieu de cela, javac
donne un avertissement s'il est lancé avec la bonne liste complète des avertissements qui peuvent être désactivés/activés liste le nom de l'avertissement empty
à cet effet. Donc 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 @ réponse nullptr . Dans IntelliJ, vous pouvez appuyer sur Ctrl + Shift + A
, entrez empty body
dans le champ de recherche et activez l'avertissement (marqué dans l'image)
Pour être honnête, il ne sert pas à grand-chose d'un point de vue minimaliste. Il existe généralement un moyen de faire avancer les choses sans une commande "ne rien faire". C'est plutôt une question de préférences personnelles, que vous préfériez
if( a() && b() );
ou
if( a() ) b();
et la même chose s'appliquerait à d'autres cas, dans lesquels le EmptyStatement
est utilisé. Un point important à considérer à 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 de EmptyStatement
- l'exemple ci-dessus compterait pour le dernier IMO.
Je peux penser à un scénario où une instruction vide est requise (pas pour la condition if
mais pour la boucle while
).
Quand un programme veut juste 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 d'autres éléments et que l'utilisateur souhaite contrôler le moment de continuer.
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
regarde ça:
int a,b,c = 0;
if(a == b){
c =1;
}
System.out.print(c);//1
vous pouvez donc écrire comme ceci:
if (a == b)c=1;
mais, si ce code est le suivant:
int a,b,c=0;
if (a != b){
}
if (a == b ){
c =1;
}
vous pouvez écrire comme ceci:
if(a != b);
if(a == b )c=1;
donc, vous saurez if(a != b);
noting
Point-virgule à la fin de,
if (a == b); il suffit de terminer l'instruction en une seule ligne, ce qui signifie ignorer le résultat de la condition et poursuivre l'exécution à partir de la ligne suivante
Ce code est utile, d'autre part introduire parfois un bogue dans le programme, par exemple,
cas 1.
a = 5;
b = 3;
if (a == b);
prinf ("a et b sont égaux");
cas 2.
a = 5;
b = 5;
if (a == b);
prinf ("a et b sont égaux");
imprimerait la même sortie à l'écran ...
Le point-virgule dans le if indique la fin de la condition if comme dans Java ;
est traité comme la fin d'une instruction, donc l'instruction après if est exécutée.