web-dev-qa-db-fra.com

Pourquoi Java a-t-il une erreur du compilateur "instruction inaccessible"?

Je trouve souvent lors du débogage d'un programme qu'il est pratique (bien que ce soit sans doute une mauvaise pratique) d'insérer une instruction return dans un bloc de code. Je pourrais essayer quelque chose comme ceci dans Java ....

class Test {
        public static void main(String args[]) {
                System.out.println("hello world");
                return;
                System.out.println("i think this line might cause a problem");
        }
}

bien sûr, cela produirait l'erreur du compilateur.

Test.Java:7: instruction inaccessible

Je pourrais comprendre pourquoi un avertissement pourrait être justifié, car avoir du code non utilisé est une mauvaise pratique. Mais je ne comprends pas pourquoi cela doit générer une erreur.

Est-ce juste Java essayer d'être une nounou, ou y a-t-il une bonne raison de faire de cette erreur une erreur du compilateur?

79
Mike

Parce que le code inaccessible n'a pas de sens pour le compilateur. S'il est primordial et plus difficile de donner du sens au code pour les utilisateurs que pour le compilateur, le compilateur est le consommateur essentiel du code. Les concepteurs de Java sont d'avis que le code qui n'a pas de sens pour le compilateur est une erreur. Leur position est que si vous avez du code inaccessible, vous avez commis une erreur qui doit être corrigée. .

Il y a une question similaire ici: Code inaccessible: erreur ou avertissement? , dans lequel l'auteur dit "Personnellement, j'estime que cela devrait être une erreur: si le programmeur écrit un morceau de code, il devrait toujours être avec l'intention de réellement l'exécuter dans un certain scénario ". Évidemment, les concepteurs de langage de Java sont d’accord).

La question de savoir si un code inaccessible devrait empêcher la compilation est une question sur laquelle il n'y aura jamais de consensus. Mais c’est pourquoi les Java l’ont fait.).


Un certain nombre de personnes dans les commentaires soulignent qu'il existe de nombreuses classes de code inaccessible Java n'empêche pas la compilation. Si je comprends correctement les conséquences de Gödel, aucun compilateur ne peut capturer toutes les classes d'inaccessible. code.

Les tests unitaires ne peuvent pas attraper tous les bogues. Nous n'utilisons pas cela comme un argument contre leur valeur. De même, un compilateur ne peut pas capturer tous les codes problématiques, mais il est toujours utile d'empêcher la compilation de mauvais code quand il le peut.

Les concepteurs de langage Java considèrent le code inaccessible comme une erreur. Donc, l’empêcher de compiler lorsque cela est possible est raisonnable.


(Avant de voter vers le bas: la question n'est pas de savoir si Java devrait avoir une erreur inaccessible du compilateur. La question est pourquoi Java a une erreur du compilateur d'instruction inaccessible. Ne me refusez pas de voter parce que vous pensez Java a pris la mauvaise décision de conception.)

61
SamStephens

Il n’existe aucune raison définitive pour laquelle des déclarations inaccessibles ne doivent pas être autorisées; d'autres langues leur permettent sans problèmes. Pour vos besoins spécifiques, voici le truc habituel:

if (true) return;

Cela semble absurde, quiconque lira le code devinera que cela doit avoir été fait délibérément et non comme une erreur de négligence de laisser le reste des déclarations inaccessible.

Java supporte un peu la "compilation conditionnelle"

http://Java.Sun.com/docs/books/jls/third_edition/html/statements.html#14.21

if (false) { x=3; }

n'entraîne pas d'erreur de compilation. Un compilateur optimiseur peut se rendre compte que l’instruction x = 3; ne sera jamais exécuté et peut choisir d'omettre le code de cette instruction à partir du fichier de classe généré, mais l'instruction x = 3; n'est pas considéré comme "inaccessible" au sens technique spécifié ici.

La raison de ce traitement différent est de permettre aux programmeurs de définir des "variables de drapeau" telles que:

static final boolean DEBUG = false;

puis écrivez un code tel que:

if (DEBUG) { x=3; }

L'idée est qu'il devrait être possible de changer la valeur de DEBUG de false en true ou de true en false, puis de compiler le code correctement sans autre modification du texte du programme.

46
irreputable

C'est nounou. Je pense que .Net l'a bien compris - il génère un avertissement pour le code inaccessible, mais pas une erreur. Il est bon d’être averti à ce sujet, mais je ne vois aucune raison d’empêcher la compilation (en particulier lors des sessions de débogage où il est agréable de retourner un message afin de contourner du code).

18
Brady Moritz

Je viens juste de remarquer cette question et je voulais ajouter mon 0,02 $ à cela.

Dans le cas de Java, ce n'est pas réellement une option. L'erreur "code inaccessible" ne provient pas du fait que les développeurs de machine virtuelle Java ont pensé protéger les développeurs de tout ce qui se passe, ou d'être extrêmement vigilant, mais des exigences de la spécification de la machine virtuelle Java.

Le compilateur Java et la machine virtuelle Java) utilisent ce qu'on appelle des "cartes de pile" - des informations précises sur tous les éléments de la pile, telles qu'attribuées pour la méthode en cours. Le type de chaque L'emplacement de la pile doit être connu, de sorte qu'une instruction JVM ne maltraite pas un élément d'un type pour un autre type. Ceci est essentiel pour éviter qu'une valeur numérique ne soit jamais utilisée comme pointeur. Il est possible d'utiliser Java Assembly, pour essayer d'envoyer/de stocker un nombre, puis d'afficher/de charger une référence d'objet. Toutefois, la machine virtuelle Java refuse ce code lors de la validation de la classe, c'est-à-dire lors de la création et de la cohérence des mappes de pile. .

Pour vérifier les mappes de pile, VM doit parcourir tous les chemins de code existant dans une méthode et vous assurer que, quel que soit le chemin de code qui sera exécuté, les données de pile de chaque L’instruction est en accord avec ce que tout code précédent a poussé/stocké dans la pile.

Object a;
if (something) { a = new Object(); } else { a = new String(); }
System.out.println(a);

à la ligne 3, JVM vérifiera que les deux branches de 'if' ont uniquement stocké dans un élément compatible (avec la variable locale var # 0) quelque chose de compatible avec Object (car c'est ainsi que le code de la ligne 3 et de la suivante traitera la variable locale # 0 ).

Lorsque le compilateur parvient à un code inaccessible, il ne sait pas exactement quel est l'état de la pile à ce moment-là, il ne peut donc pas vérifier son état. Il ne peut plus compiler le code à ce stade, car il ne peut pas non plus garder une trace des variables locales. Ainsi, au lieu de laisser cette ambiguïté dans le fichier de classe, une erreur fatale est générée.

Bien sûr, une condition simple telle que if (1<2) le trompera, mais ce n'est pas vraiment duper - cela lui donne une branche potentielle pouvant mener au code, et au moins le compilateur et le VM peut déterminer comment les éléments de la pile peuvent être utilisés à partir de là.

P.S. Je ne sais pas ce que fait NET dans ce cas, mais je pense que la compilation échouera également. Ce ne sera normalement pas un problème pour les compilateurs de code machine (C, C++, Obj-C, etc.)

14
Pawel Veselov

L'un des objectifs des compilateurs est d'éliminer les classes d'erreurs. Il y a du code inaccessible par accident, c’est bien que javac exclue cette classe d’erreur au moment de la compilation.

Pour chaque règle qui intercepte un code erroné, quelqu'un voudra que le compilateur l'accepte car il sait ce qu'il fait. C'est la peine de vérifier le compilateur, et trouver le bon équilibre est l'un des points les plus délicats de la conception de langage. Même avec les contrôles les plus stricts, un nombre infini de programmes peuvent être écrits. Les choses ne peuvent donc pas être aussi mauvaises.

5
Ricky Clarkson

Bien que je pense que cette erreur du compilateur est une bonne chose, il existe un moyen de la contourner. Utilisez une condition que vous savez être vraie:

public void myMethod(){

    someCodeHere();

    if(1 < 2) return; // compiler isn't smart enough to complain about this

    moreCodeHere();

}

Le compilateur n'est pas assez intelligent pour s'en plaindre.

5
Sean Patrick Floyd

C’est certainement une bonne chose de se plaindre que plus le compilateur est strict, mieux il vous permet de faire ce dont vous avez besoin. Habituellement, le petit prix à payer est de commenter le code, le gain est que lorsque vous compilez votre code, cela fonctionne. Haskell est un exemple général dans lequel les gens hurlent jusqu'à ce qu'ils réalisent que leur test/débogage est un test principal uniquement. Je personnellement dans Java ne fais presque pas de débogage tout en étant (en fait exprès) pas attentif.

0

Si la raison d'autoriser if (aBooleanVariable) return; someMoreCode; est d'autoriser les drapeaux, le fait que if (true) return; someMoreCode; ne génère pas d'erreur de compilation semble être une incohérence dans la politique de génération d'une exception CodeNotReachable, car le compilateur sait que true n'est pas un drapeau (ni une variable).

Deux autres manières qui pourraient être intéressantes, mais ne s'appliquent pas à la désactivation d'une partie du code d'une méthode, ainsi que if (true) return:

Maintenant, au lieu de dire if (true) return;, vous pourriez vouloir dire assert false Et ajouter -ea OR -ea package OR -ea className Aux arguments jvm. Le point positif est que cela permet une certaine granularité et nécessite l'ajout d'un paramètre supplémentaire à l'invocation de jvm, de sorte qu'il n'est pas nécessaire de définir un indicateur DEBUG dans le code, mais en ajoutant un argument à l'exécution, ce qui est utile lorsque la cible n'est pas la cible. développeur et recompiler et transférer le bytecode prend du temps.

Il y a aussi le chemin System.exit(0), mais il peut s'agir d'une surcharge, si vous le mettez dans Java dans un JSP, le serveur sera alors arrêté.

En dehors de cela Java est un langage de "nounou", je préférerais utiliser quelque chose de natif comme C/C++ pour plus de contrôle.

0
MichaelS