5.3 Wertebereich eines Typs und Überlaufkontrolle 

Die Klassen Byte, Short, Integer, Long, Float und Double besitzen die Konstanten MIN_VALUE und MAX_VALUE für den minimalen und maximalen Wertebereich. Die Klassen Float und Double verfügen zusätzlich über die wichtigen Konstanten NEGATIVE_INFINITY und POSITIVE_INFINITY für minus und plus unendlich und NaN (Not a Number, undefiniert).
Hinweis Integer.MIN_VALUE steht mit –2147483648 für den kleinsten Wert, den die Ganzzahl annehmen kann. Double.MIN_VALUE steht jedoch für die kleinste positive Zahl (beste Näherung an 0), die ein Double darstellen kann (4.9E–324). |
Alle Wrapper-Klassen überschreiben toString() von Object so, dass sie eine String-Repräsentation des Objekts zurückgeben.
5.3.1 Behandlung des Überlaufs 

Bei einigen mathematischen Fragestellungen müssen Sie feststellen können, ob Operationen wie die Addition, Subtraktion oder Multiplikation den Zahlenbereich sprengen, also etwa den Ganzzahlenbereich eines Integers von 32 Bit verlassen. Passt das Ergebnis einer Berechnung nicht in den Wertebereich einer Zahl, so wird dieser Fehler nicht von Java angezeigt; weder der Compiler noch die Laufzeitumgebung melden dieses Problem. Es gibt auch keine Ausnahme.
Mathematisch gilt a * a / a = a, also zum Beispiel 100 000 * 100 000 / 100 000 = 100 000. In Java ist das anders, da wir bei 100 000 * 100 000 einen Überlauf im int haben.
System.out.println( 100000 * 100000 / 100000 ); // 14100
liefert daher 14100. Wenn wir den Datentyp auf long erhöhen, indem wir hinter ein 100 000 ein L setzen, sind wir bei dieser Multiplikation noch sicher, da ein long das Ergebnis aufnehmen kann.
System.out.println( 100000L * 100000 / 100000 ); // 100000
Überlauf erkennen
Für die Operationen Addition und Subtraktion lässt sich das noch ohne allzu großen Aufwand implementieren. Wir vergleichen dazu zunächst das Ergebnis mit den Konstanten Integer.MAX_VALUE und Integer.MIN_VALUE. Natürlich muss der Vergleich so umgeformt werden, dass dabei kein Überlauf auftritt, also a + b > Integer.MAX_VALUE ist. Überschreiten die Werte diese maximalen Werte, ist die Operation nicht ohne Fehler möglich, und wir setzen das Flag canAdd auf false. Hier die Programmzeilen für die Addition:
if ( a >=0 && b >= 0 ) if ( ! (b <= Integer.MAX_VALUE – a) ) canAdd = false; if ( a < 0 && b < 0 ) if ( ! (b >= Integer.MIN_VALUE – a) ) canAdd = false;
Bei der Multiplikation gibt es zwei Möglichkeiten: Zunächst einmal lässt sich die Multiplikation als Folge von Additionen darstellen. Dann ließe sich wiederum der Test mit der Konstanten Integer.XXX_VALUE durchführen. Diese Lösung scheidet jedoch wegen der Geschwindigkeit aus. Der andere Weg sieht eine Umwandlung nach long vor. Das Ergebnis wird zunächst als long berechnet und anschließend mit dem Ganzzahlwert vom Typ int verglichen.
Dies funktioniert jedoch nur mit Datentypen, die kleiner als long sind. long selbst fällt heraus, da es keinen Datentyp gibt, der größer ist. Mit ein wenig Rechenungenauigkeit würde ein double jedoch weiterhelfen, und bei präziserer Berechnung kann BigInteger helfen. Bei der Multiplikation im Wertebereich int lässt sich ähnlich wie bei der Addition auch b > Integer.MAX_VALUE / a schreiben. Bei b == Integer.MAX_VALUE / a muss ein Test genau zeigen, ob das Ergebnis in den Wertebereich passt.
Die folgende Funktion canMulLong() soll bei der Frage nach dem Überlauf helfen:
Listing 5.2 Overflow.java
import java.math.BigInteger; public class Overflow { private final static BigInteger MAX = BigInteger.valueOf( Long.MAX_VALUE ); public static boolean canMulLong( long a, long b ) { BigInteger bigA = BigInteger.valueOf( a ); BigInteger bigB = BigInteger.valueOf( b ); return bigB.multiply( bigA ).compareTo( MAX ) <= 0; } public static void main( String[] args ) { System.out.println( canMulLong(Long.MAX_VALUE/2, 2) ); // true System.out.println( Long.MAX_VALUE/2 * 2 ); // 9223372036854775806 System.out.println( canMulLong(Long.MAX_VALUE/2 + 1, 2) ); // false System.out.println( (Long.MAX_VALUE/2 + 1) * 2 ); //-9223372036854775808 } }