3. Dépassements de capacité

Il existe deux types de dépassements de capacités : ceux sur les entiers et ceux sur les flottants. Lors d'opérations sur les entiers, aucune erreur n'est levée lors d'un dépassement de capacité. Comme dans la plupart des langages, incrémenter un très grand entier positif finit par donner un entier négatif de très grande valeur absolue. En fait, la seule erreur levée lors d'opération sur les entiers est la division par zéro. Il en va différemment pour les flottants, comme nous allons le voir.

3.1. Cas des entiers

Comme la plupart des langages, Java utilise le complément à 2 pour coder les entiers négatifs, ce qui fait que lorsque l’on ajoute 1 au plus grand entier positif codable, on obtient comme résultat l’entier négatif le plus grand en valeur absolue. Ces plus grandes valeurs existent sous forme de constantes dans la classe Integer :

Exemple 65. Plus grandes valeurs de la classe Integer

public  static  final  int MAX_VALUE =  0x7fffffff ;  
 public  static  final  int MIN_VALUE =  0x80000000 ;

Il existe les mêmes valeurs pour les byte dans la classe Byte, pour les short dans la classe Short etc… Mis à part la division par zéro, il n’y a pas d’erreur générée pour les dépassements de capacités sur les opérations entières.

Exemple 66. Cas de la division par 0

int i =  0 ;  
 int j =  9 ;  
  
 int k = j / i ;  // génère une java.lang.ArithmeticException

3.2. Cas des flottants

Le cas des nombres en virgule flottante est un peu différent, car ils ont en fait quatre limites : un plus grand nombre positif, un plus petit nombre positif, et les deux équivalents négatifs. Ces limites sont aussi stockées dans les classes Float et Double.

Exemple 67. Limites de codage des Float et Double

// Classe Float  
 public  static  final  int MIN_VALUE =  1.4E-45 ;  
 public  static  final  int MAX_VALUE =  3.4028235E38 ;

 // Classe Double  
 public  static  final  int MIN_VALUE =  4.9E-324 ;  
 public  static  final  int MAX_VALUE =  1.7976931348623157E308 ;

Quand un résultat en virgule flottante devient plus petit qu’une des valeurs minimales, il est mis à 0. Quand il dépasse la plus grande valeur codable, il prend la valeur POSITIVE_INFINITY ou NEGATIVE_INFINITY suivant qu’il est positif ou négatif respectivement. En particulier, la division par 0 ne génère pas d'erreur en flottant : elle donne un résultat qui est soit POSITIVE_INFINITY soit NEGATIVE_INFINITY. Quand le résultat a une valeur indéfinie, il prend la valeur NaN ( Not a Number ). Cela arrive dans quatre cas :
  • la division de 0 par 0 ;
  • la soustraction de *_INFINITY à lui-même ;
  • la division de *_INFINITY par lui-même ;
  • la multiplication *_INFINITY par 0.
La valeur NaN a une particularité : elle n’est égale à rien, pas même à elle-même ! Pour savoir si le résultat d’une expression a la valeur NaN, il ne faut donc pas tenter de la comparer à NaN avec un naïf ==, mais utiliser la méthode isNaN(), comme sur l’exemple suivant.

Exemple 68. Test si un nombre vaut NaN

if (Float.isNaN(0F/0F))  // le résultat de ce test est vrai

Voyons un exemple de division par 0 en flottant.

Exemple 69. Exemple de division par 0 en flottant

double p =  0.0 ;  
 double q =  0.0 ;  
  
 double r = p / q ;  // pas d'erreur à l'exécution  
 double t = p / q ;  
 double u = r ;  
   
System.out.println("r = " + r) ;  
System.out.println("r == t : " + (r == t)) ;  
System.out.println("r == u : " + (r == u)) ;

Voici le résultat de cette exécution :
 > r = NaN
 > r == t : false
 > r == u : false
Comme prévu, on constate que NaN n'est égal à rien.

3.3. Bibliothèques BigInteger et BigDecimal

La librairie mathématique standard contient deux classes : BigInteger et BigDecimal qui permettent de travailler en entier et en flottant avec une précision arbitraire. Ces classes sont utilisées lorsque l'on veut faire des calculs sur des nombres de grande précision. La précision est en fait simulée par logiciel, ce qui fait que les calculs qui utilisent ces classes peuvent être très lents. Leur utilisation dans les cas courants est totalement déconseillée. Il existe en revanche certaines applications ou elles sont indispensables. Les nombres de ce type sont des objets, réaliser des opérations dessus se fait donc de la façon suivante.

Exemple 70. Utilisation de BigInteger

BigInteger i =  new BigInteger("123") ;  
BigInteger j =  new BigInteger("345") ;  
BigInteger k = i.add(j) ;

Java langage & API
Retour au blog Java le soir
Cours & Tutoriaux
Table des matières
Introduction : un peu d'histoire
1. Java : genèse d'un nouveau langage
Programmer en Java
1. Un premier exemple
1.1. Aperçu général, cycle de vie
1.2. Un premier programme
1.3. Programmes, applets, servlets, etc...
2. Une première classe
2.1. Écriture d'une classe
2.2. Instanciation de cette classe
3. Types de base, classes et objets
3.1. Types de base
3.2. Classes et objets
Classes Object et String
1. Introduction
2. La classe Object
2.1. La méthode toString()
2.2. La méthode clone()
2.3. La méthode equals()
2.4. La méthode hashCode()
2.5. La méthode finalize()
2.6. La méthode getClass()
3. La classe String
3.1. Introduction
3.2. Construction d'un objet de type String
3.3. Concaténation, StringBuffer et StringBuilder
3.4. Concaténations de chaînes de caractères depuis Java 8
3.5. Concaténations de chaînes de caractères depuis Java 11
3.6. Extraction d'une sous-chaîne de caractères
3.7. Comparaison de deux chaînes de caractères
3.8. Méthodes de comparaisons lexicographiques
3.9. Méthode de recherche de caractères
3.10. Méthode de modification de chaîne
3.11. Méthode de duplication
3.12. Support de l'unicode, internationalisation
Structure d'une classe
1. Introduction
2. Classes
2.1. Classes publiques
2.2. Classes internes
2.3. Classe membre
2.4. Classes locales
2.5. Classes anonymes
2.6. Le mot-clé this
3. Éléments statiques
3.1. Champ statique
3.2. Cas des constantes
3.3. Bloc statique
3.4. Classe membre statique
4. Membres d'une classe, visibilité
4.1. Bloc non statique
4.2. Accès à un membre, visibilité
4.3. Les champs
4.4. Signature d'une méthode
4.5. Les méthodes
4.6. Getters et Setters
5. Constructeur, instanciation
5.1. Chargement d'une classe
5.2. Constructeurs d'une classe
5.3. Instanciation d'un objet
5.4. Destruction d'objets
5.5. Le mot-clé final
6. Énumérations
6.1. Déclaration d'une énumération
6.2. Classe énumération
6.3. Méthode toString()
6.4. Méthode valueOf()
6.5. Méthode values()
6.6. Méthode ordinal()
6.7. Méthode compareTo()
6.8. Constructeurs privés
6.9. Classe utilitaire : EnumSet
Noms, opérateurs, tableaux
1. Introduction
2. Identificateurs, noms et expressions
2.1. Identificateurs et noms
2.2. Expressions
3. Opérateurs, ordre d'exécution
3.1. Ordre d'exécution
3.2. Les opérateurs
3.3. Les opérateurs ++ et --
3.4. Les opérateurs % et /
3.5. Les opérateurs <<, >> et >>>
3.6. L'opérateur instanceof
3.7. Les opérateurs &, | et ^
3.8. Les opérateurs && et ||
3.9. L'opérateur ? ... :
3.10. Les opérateurs d'affectation
4. Tableaux
4.1. Création d'un tableau
4.2. Initialisation d'un tableau
4.3. Utilisation d'un tableau comme un Object
4.4. Tableaux de tableaux
4.5. Copie de tableaux
5. Blocs, boucles et contrôles
5.1. Blocs
5.2. Mots-clés réservés
5.3. Tests : if et switch
5.4. Boucles : for, while, do ... while
5.5. Commandes continue et break
5.6. Commandes return et goto
Nombres, précision, calculs
1. Introduction
2. Calculs
2.1. Précision
2.2. Codage des nombres flottants
2.3. Le mot-clé strictfp
2.4. Conversion de types
3. Dépassements de capacité
3.1. Cas des entiers
3.2. Cas des flottants
3.3. Bibliothèques BigInteger et BigDecimal
4. Fonctions mathématiques
4.1. Fonctions usuelles
4.2. Générateurs aléatoires
5. Classes enveloppe
5.1. Associer les types de base à des objets
5.2. Auto-boxing
Héritage, abstraction, interfaces
1. Introduction
2. Abstraction et encapsulation
2.1. Abstraction
2.2. Encapsulation
3. Héritage
3.1. Définition de l'héritage
3.2. Conséquences pour les membres
3.3. Polymorphisme
3.4. Empêcher l'héritage
4. Classes abstraites
5. Interfaces
5.1. Introduction
5.2. Définition
5.3. Java 8 et les interfaces
5.4. Utilisation des interfaces
5.5. Définition de constantes dans les interfaces
5.6. Utilité des interfaces
Packages
1. Introduction
2. Notion de paquet
2.1. Déclaration d’appartenance à un paquet
2.2. Chargement d’une classe
2.3. Choix de nom
3. Archives, chemin de recherche, classpath
3.1. Archives
3.2. Variable CLASSPATH
3.3. Notion de classloader
3.4. Bilan sur les classes chargées
3.5. Visibilité
3.6. Conseils d'écriture, bibliothèque standard
Exceptions
1. Introduction
2. Erreurs et Exceptions
2.1. Classe Throwable, notion de stack trace
2.2. Classe Error
2.3. Classe RuntimException
2.4. Classe Exception
3. Déclenchement d'une exception
3.1. Exceptions déclenchées par la JVM
3.2. Exceptions déclenchées par l'application
4. Capter une exception
4.1. Traiter une exception localement
4.2. Code de captage
5. Créer ses propres exceptions
Entrées / sorties
1. Introduction
2. Notion de fichier
2.1. Introduction
2.2. La classe File
2.3. Construction d'une instance de File
2.4. Méthodes exposées
3. Flux de sortie
3.1. Introduction, notion de flux
3.2. Écriture de caractères, classe Writer
3.3. Bufferisation, construction d'un flux sur un autre
3.4. Utilisation de PrintWriter
3.5. Écriture d'octets, OuputStream
3.6. Écriture de types primitifs : DataOutputStream
3.7. Écriture d'objets : ObjectOutputStream
4. Flux d'entrée
4.1. Introduction
4.2. Lecture de caractères, classe Reader
4.3. Bufferisation, lecture ligne par ligne
4.4. Lecture d'octets : InputStream
4.5. Lecture de types primitifs : DataInputStream
4.6. Lecture d'objets : ObjectInputStream
5. Lecture et écriture de flux croisés
5.1. Introduction
5.2. Lire des caractères sur un flux binaire : classe InputStreamReader
5.3. Écrire des caractères sur un flux binaire : classe OutputStreamWriter
5.4. Remarque sur les jeux de caractères
6. Serialization d'objets
6.1. Enjeu de la sérialization d'objets
6.2. Serialization d'un objet
6.3. Sérialization d'une grappe d'objets
6.4. Première surcharge : méthode writeObject() readObject()
6.5. Deuxième surcharge : utilisation d'un externalizer
6.6. Troisième surcharge : utilisation d'un objet proxy
7. Flux compressés
7.1. Introduction
7.2. Flux de type gzip
7.3. Flux de type zip