Je lisais cette question sur SO qui discute d'un comportement non défini commun en C ++, et je me suis demandé: Java a-t-il également un comportement non défini?
Si tel est le cas, quelles sont les causes courantes de comportement indéfini en Java?
Sinon, quelles fonctionnalités de Java le rendent exempt de tels comportements et pourquoi les dernières versions de C et C ++ n'ont-elles pas été implémentées avec ces propriétés?
java
c++
c
undefined-behavior
Huit
la source
la source
Réponses:
En Java, vous pouvez considérer que le comportement d'un programme mal synchronisé n'est pas défini.
Java 7 JLS utilise le mot "non défini" une fois, en 17.4.8. Exécutions et conditions de causalité :
La documentation de l'API Java spécifie certains cas où les résultats ne sont pas définis - par exemple, dans le constructeur (obsolète) Date (int année, mois int, jour int) :
État des Javadocs pour ExecutorService.invokeAll (Collection) :
Un type moins formel de comportement "non défini" peut être trouvé par exemple dans ConcurrentModificationException , où les documents API utilisent le terme "meilleur effort":
appendice
L'un des commentaires de la question fait référence à un article d'Eric Lippert qui fournit une introduction utile aux sujets: le comportement défini par l'implémentation .
Je recommande cet article pour le raisonnement indépendant du langage, même s'il convient de garder à l'esprit que l'auteur cible C #, pas Java.
Ci-dessus est seulement une couverture très brève; l'article complet contient des explications et des exemples pour les points mentionnés dans cet extrait; cela vaut la peine d' être lu. Par exemple, les détails fournis pour le "sixième facteur" peuvent donner un aperçu de la motivation de nombreuses instructions dans le modèle de mémoire Java ( JSR 133 ), aidant à comprendre pourquoi certaines optimisations sont autorisées, conduisant à un comportement indéfini tandis que d'autres sont interdites, conduisant à limitations telles que les conditions de survenance et de causalité .
la source
Du haut de ma tête, je ne pense pas qu'il y ait un comportement indéfini en Java, du moins pas dans le même sens qu'en C ++.
La raison en est qu'il y a une philosophie différente derrière Java que derrière C ++. L'un des principaux objectifs de conception de Java était de permettre aux programmes de fonctionner sans changement sur toutes les plateformes, de sorte que la spécification définit tout de manière très explicite.
En revanche, un objectif de conception de base de C et C ++ est l'efficacité: il ne devrait pas y avoir de fonctionnalités (y compris l'indépendance de la plate-forme) qui coûtent les performances même si vous n'en avez pas besoin. À cette fin, la spécification ne définit pas délibérément certains comportements, car leur définition entraînerait un travail supplémentaire sur certaines plates-formes et réduirait ainsi les performances, même pour les personnes qui écrivent des programmes spécifiquement pour une plate-forme et connaissent toutes ses particularités.
Il y a même un exemple où Java a été contraint d'introduire rétroactivement une forme limitée de comportement indéfini pour exactement cette raison: le mot clé strictfp a été introduit dans Java 1.2 pour permettre aux calculs en virgule flottante de s'écarter de suivre exactement la norme IEEE 754 comme la spécification l'avait précédemment demandé , car cela nécessitait un travail supplémentaire et rendait tous les calculs à virgule flottante plus lents sur certains processeurs courants, tout en produisant des résultats moins bons dans certains cas.
la source
int x=-1; foo(); x<<=1;
la philosophie hyper-moderne, il serait préférable de réécrirefoo
afin que tout chemin qui ne quitte pas soit inaccessible. Ce, sifoo
estif (should_launch_missiles) { launch_missiles(); exit(1); }
un compilateur pourrait (et selon certaines personnes devraient) simplifier que simplementlaunch_missiles(); exit(1);
. L'UB traditionnel était l'exécution de code aléatoire, mais celle-ci était liée par les lois du temps et de la causalité. Le nouvel UB amélioré n'est lié par aucun des deux.Java essaie assez fort d'exterminer les comportements indéfinis, précisément à cause des leçons des langages antérieurs. Par exemple, les variables de niveau classe sont automatiquement initialisées; les variables locales ne sont pas auto-initialisées pour des raisons de performances, mais il existe une analyse de flux de données sophistiquée pour empêcher quiconque d'écrire un programme qui serait capable de détecter cela. Les références ne sont pas des pointeurs, les références non valides ne peuvent donc pas exister et le déréférencement
null
provoque une exception spécifique.Bien sûr, certains comportements ne sont pas entièrement spécifiés et vous pouvez écrire des programmes peu fiables si vous supposez qu'ils le sont. Par exemple, si vous parcourez une normale (non triée)
Set
, le langage garantit que vous verrez chaque élément exactement une fois, mais pas dans quel ordre vous les verrez. L'ordre peut être le même sur des séries successives, ou il peut changer; ou il peut rester le même tant qu'aucune autre allocation ne se produit, ou tant que vous ne mettez pas à jour votre JDK, etc. Il est presque impossible de se débarrasser de tous ces effets; par exemple, vous devrez explicitement ordonner ou randomiser toutes les opérations de collections, et cela ne vaut tout simplement pas le petit un-undefined-ness supplémentaire.la source
Vous devez comprendre le "comportement indéfini" et son origine.
Un comportement indéfini signifie un comportement qui n'est pas défini par les normes. C / C ++ a trop d'implémentations de compilateur différentes et de fonctionnalités supplémentaires. Ces fonctionnalités supplémentaires ont lié le code au compilateur. En effet, il n'y avait pas de développement de langage centralisé. Ainsi, certaines des fonctionnalités avancées de certains compilateurs sont devenues des "comportements non définis".
Alors qu'en Java la spécification du langage est contrôlée par Sun-Oracle et personne d'autre n'essaye de faire des spécifications et donc aucun comportement indéfini.
Édité répondant spécifiquement à la question
la source
Java élimine essentiellement tous les comportements non définis trouvés en C / C ++. (Par exemple: débordement d'entier signé, division par zéro, variables non initialisées, déréférence de pointeur nul, décalage de plus de largeur de bit, double-free, même "pas de nouvelle ligne à la fin du code source".) Mais Java a quelques comportements obscurs non définis qui sont rarement rencontrés par les programmeurs.
Java Native Interface (JNI), un moyen pour Java d'appeler du code C ou C ++. Il existe de nombreuses façons de bousiller JNI, comme se tromper de signature de fonction, passer des appels invalides aux services JVM, corrompre la mémoire, allouer / libérer des choses de manière incorrecte, etc. J'ai déjà fait ces erreurs, et généralement la JVM entière se bloque lorsqu'un thread exécutant du code JNI commet une erreur.
Thread.stop()
, qui est obsolète. Citation:https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
la source