Eh bien, en ce qui concerne les types entiers primitifs, Java ne gère pas du tout les débordements / débordements (pour flottant et double, le comportement est différent, il s'écoulera à +/- infini tout comme les mandats IEEE-754).
Lorsque vous ajoutez deux int, vous n'obtiendrez aucune indication lorsqu'un débordement se produit. Une méthode simple pour vérifier le débordement consiste à utiliser le type plus grand suivant pour réellement effectuer l'opération et vérifier si le résultat est toujours dans la plage du type source:
public int addWithOverflowCheck(int a, int b) {
// the cast of a is required, to make the + work with long precision,
// if we just added (a + b) the addition would use int precision and
// the result would be cast to long afterwards!
long result = ((long) a) + b;
if (result > Integer.MAX_VALUE) {
throw new RuntimeException("Overflow occured");
} else if (result < Integer.MIN_VALUE) {
throw new RuntimeException("Underflow occured");
}
// at this point we can safely cast back to int, we checked before
// that the value will be withing int's limits
return (int) result;
}
Ce que vous feriez à la place des clauses throw dépend des exigences de vos applications (throw, flush to min / max ou tout simplement enregistrer quoi que ce soit). Si vous voulez détecter un débordement sur de longues opérations, vous n'avez pas de chance avec les primitives, utilisez plutôt BigInteger.
Edit (2014-05-21): Étant donné que cette question semble être évoquée assez fréquemment et que j'ai dû résoudre le même problème moi-même, il est assez facile d'évaluer la condition de débordement par la même méthode qu'un processeur calculerait son indicateur V.
C'est fondamentalement une expression booléenne qui implique le signe des deux opérandes ainsi que le résultat:
/**
* Add two int's with overflow detection (r = s + d)
*/
public static int add(final int s, final int d) throws ArithmeticException {
int r = s + d;
if (((s & d & ~r) | (~s & ~d & r)) < 0)
throw new ArithmeticException("int overflow add(" + s + ", " + d + ")");
return r;
}
En java, il est plus simple d'appliquer l'expression (dans le if) aux 32 bits entiers et de vérifier le résultat en utilisant <0 (cela testera efficacement le bit de signe). Le principe fonctionne exactement de la même manière pour tous les types primitifs entiers , en changeant toutes les déclarations de la méthode ci-dessus en long, cela fonctionne longtemps.
Pour les types plus petits, en raison de la conversion implicite en int (voir le JLS pour les opérations au niveau du bit pour plus de détails), au lieu de vérifier <0, la vérification doit masquer explicitement le bit de signe (0x8000 pour les opérandes courts, 0x80 pour les opérandes d'octets, ajuster les conversions et déclaration des paramètres):
/**
* Subtract two short's with overflow detection (r = d - s)
*/
public static short sub(final short d, final short s) throws ArithmeticException {
int r = d - s;
if ((((~s & d & ~r) | (s & ~d & r)) & 0x8000) != 0)
throw new ArithmeticException("short overflow sub(" + s + ", " + d + ")");
return (short) r;
}
(Notez que l'exemple ci-dessus utilise l'expression besoin de soustraire la détection de débordement)
Alors, comment / pourquoi ces expressions booléennes fonctionnent-elles? Tout d'abord, une réflexion logique révèle qu'un débordement ne peut se produire que si les signes des deux arguments sont les mêmes. Parce que, si un argument est négatif et un positif, le résultat (de l'addition) doit être plus proche de zéro, ou dans le cas extrême un argument est nul, le même que l'autre argument. Comme les arguments ne peuvent pas créer par eux-mêmes une condition de débordement, leur somme ne peut pas non plus créer de débordement.
Que se passe-t-il donc si les deux arguments ont le même signe? Jetons un coup d'œil au cas où les deux sont positifs: l'ajout de deux arguments qui créent une somme supérieure aux types MAX_VALUE, produira toujours une valeur négative, donc un débordement se produit si arg1 + arg2> MAX_VALUE. Maintenant, la valeur maximale qui pourrait en résulter serait MAX_VALUE + MAX_VALUE (le cas extrême, les deux arguments sont MAX_VALUE). Pour un octet (exemple) qui signifierait 127 + 127 = 254. En regardant les représentations binaires de toutes les valeurs qui peuvent résulter de l'ajout de deux valeurs positives, on constate que celles qui débordent (128 à 254) ont toutes le bit 7 défini, tandis que tout ce qui ne déborde pas (0 à 127) a le bit 7 (le plus haut, signe) effacé. C'est exactement ce que la première partie (à droite) de l'expression vérifie:
if (((s & d & ~r) | (~s & ~d & r)) < 0)
(~ s & ~ d & r) devient vrai, seulement si deux opérandes (s, d) sont positifs et que le résultat (r) est négatif (l'expression fonctionne sur les 32 bits, mais le seul bit qui nous intéresse est le bit (signe) le plus haut, qui est vérifié par le <0).
Maintenant, si les deux arguments sont négatifs, leur somme ne peut jamais être plus proche de zéro que n'importe lequel des arguments, la somme doit être plus proche de moins l'infini. La valeur la plus extrême que nous pouvons produire est MIN_VALUE + MIN_VALUE, qui (là encore pour l'exemple d'octet) montre que pour toute valeur dans la plage (-1 à -128), le bit de signe est défini, tandis que toute valeur de débordement possible (-129 à -256 ) a le bit de signe effacé. Ainsi, le signe du résultat révèle à nouveau la condition de débordement. C'est ce que la moitié gauche (s & d & ~ r) vérifie pour le cas où les deux arguments (s, d) sont négatifs et un résultat positif. La logique est largement équivalente au cas positif; tous les modèles de bits qui peuvent résulter de l'ajout de deux valeurs négatives verront le bit de signe effacé si et seulement si un dépassement de capacité s'est produit.