web-dev-qa-db-fra.com

Point-virgule à la fin de la déclaration «si»

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?

65
Erik Bergsten

Pourquoi cela arrive-t-il?

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);

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 de 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'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.

84
Marcin Szymczak

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.

28
Tim Medora

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.

19
gefei

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

Java->Compiler->Errors/Warnings

11
nullptr

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) {
    ;
}
7
André Stannek

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.

6
Edwin Buck

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.

5
Peter Lawrey

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.

4
yshavit

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.

3
user34537

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.

2
Mukul Goel

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.

2
AgilePro
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.

1
Matt Clark

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

Les blocs sont des déclarations

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.

La clause if

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.

Mais pourquoi ça marche? ?

; 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.

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

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)

IntelliJ enable empty-body warning

À quoi cela sert-il même?

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.

1
Paul

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
0
Parvez

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

0
DMW

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 ...

0
Narayan Bhandari

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.

0
Bishal Jaiswal