Si j'essaye de compiler

for(;;)
{

}
System.out.println("End");

Le compilateur Java produit une erreur indiquant Unreachable statement. Mais si j'ajoute une autre déclaration " inaccessible " (selon moi) break et la fais:

for(;;)
{
    if(false) break;
}
System.out.println("End");

Il compile. Pourquoi ne produit-il pas d'erreur?

58
dryairship 24 déc. 2015 à 16:30

5 réponses

Meilleure réponse

Le comportement est défini dans la description JLS des instructions inaccessibles :

L'instruction then est accessible ssi l'instruction if-then est accessible.

Ainsi, le compilateur détermine que l'instruction then (break;) est accessible, quelle que soit la condition dans if.

Et un peu plus loin, je souligne le mien:

Une instruction de base for peut se terminer normalement ssi au moins une des conditions suivantes est vraie:

  • L'instruction for est accessible, il existe une expression de condition et l'expression de condition n'est pas une expression constante (§15.28) avec la valeur true.
  • Il existe une instruction break accessible qui quitte l'instruction for.

Ainsi, le for peut se terminer normalement car l'instruction then contient un break. Comme vous l'avez remarqué, cela ne fonctionnerait pas si vous remplaçiez break par return.


La justification est expliquée vers la fin de la section. En substance, if a un traitement spécial pour autoriser les constructions telles que:

if(DEBUG) { ... }

Où DEBUG peut être une constante de temps de compilation.

56
assylias 24 déc. 2015 à 13:57

Comme expliqué dans ma réponse à une question similaire, la construction spécifique if(compile-time-false) est exemptée des règles d'inaccessibilité en tant que porte dérobée explicite. Dans ce cas, le compilateur traite votre break comme accessible à cause de cela.

11
Community 23 mai 2017 à 12:16

Depuis le JLS

Une instruction if-then peut se terminer normalement si au moins l'une des conditions suivantes est vraie:

& gt; L'instruction if-then est accessible et l'expression de condition n'est pas une expression constante dont la valeur est vraie.

& gt; L'instruction then peut se terminer normalement.

Donc if(false) est autorisé.

Cette capacité à «compiler conditionnellement» a un impact significatif sur la compatibilité binaire et sa relation avec celle-ci. Si un ensemble de classes utilisant une telle variable "flag" est compilé et que le code conditionnel est omis, il ne suffit pas de distribuer plus tard simplement une nouvelle version de la classe ou de l'interface contenant la définition de l'indicateur. Une modification de la valeur d'un indicateur n'est donc pas compatible binaire avec les binaires préexistants. (Il existe également d'autres raisons à une telle incompatibilité, telles que l'utilisation de constantes dans les étiquettes case dans les instructions switch;)

7
Mohammed Aouf Zouag 24 déc. 2015 à 13:40

Fondamentalement, le code inaccessible est détecté en analysant le programme statiquement sans exécutant réellement le code. Alors que la condition sera vérifiée à l ' exécution . Ainsi, lorsque cette analyse a lieu, elle ne regarde pas réellement la condition mais vérifie simplement que break; est accessible ( accessible ) via if.

4
CoderCroc 24 déc. 2015 à 16:23

La principale raison pour laquelle Java ne détecte pas toutes les instructions inaccessibles est qu'il est généralement impossible de répondre si le code est accessible ou non. Cela découle du fait que le problème d'arrêt est indécidable sur les machines de Turing.

Il est donc clair que toutes les instructions inaccessibles ne peuvent pas être détectées, mais pourquoi ne pas essayer d'évaluer les conditions? Imaginez maintenant que la condition utilisée n'est pas seulement false mais quelque chose comme ~x == x. Par exemple, toutes ces déclarations seront imprimées true pour chaque int x (source ).

    System.out.println((x + x & 1) == 0);
    System.out.println((x + -x & 1) == 0);
    System.out.println((-x & 1) == (x & 1));
    System.out.println(((-x ^ x) & 1) == 0);
    System.out.println((x * 0x80 & 0x56) == 0);
    System.out.println((x << 1 ^ 0x1765) != 0);

Les déclarations peuvent être assez compliquées; il faut du temps pour les résoudre. Cela augmenterait considérablement le temps de construction et après tout, il ne détectera pas toutes les instructions inaccessibles. Le compilateur a été conçu pour prendre quelques efforts mais pas trop de temps pour cela.

La seule question qui reste est: où arrêter de résoudre les conditions? Les raisons de cela ne semblent pas avoir de justification mathématique et sont basées sur un scénario d'utilisation. La justification de votre cas particulier est donnée par JLS -14.21

1
Sergey Fedorov 30 déc. 2015 à 09:21