25 Copyright 1996-1997 by Axel T. Schreiner. All Rights Reserved. Integer-Daten Hier betrachten wir die verschiedenen Integer-Typen , Konstanten und Operationen . int/Ranges illustriert vor allem Bit-Operationen, int/Try zeigt, wie man eine Division durch Null abfängt. Für die einfachen Datentypen gibt es auch Klassen. int/Cvt verwendet einige Klassenmethoden aus der Integer-Klasse zur Umwandlung zwischen Text und Integer-Werten. Außerdem gibt es Byte , Short und Long . Typen und Wertbereiche Java kennt nur Integer mit Vorzeichen, strikt definierten Wertbereichen und Repräsentierung im Zweierkomplement. byte short int long 8 Bit 16 Bit 32 Bit 64 Bit -128 -32768 -2147483648 -9223372036854775808 127 32767 2147483647 9223372036854775807 Konstanten Konstanten werden mit Präfix 0x oder 0X in Basis 16, mit Präfix 0 in Basis 8 und sonst dezimal interpretiert; mit Suffix l oder L haben sie den Typ long, sonst int. Dezimale Konstanten müssen im positiven Wertbereich liegen. Operationen Integer-Werte können von und zu Integer- und Gleitkomma-Werten umgewandelt werden, aber nicht von und zu boolean . sowie char Es gibt die üblichen Operatoren: Vorzeichen + - ~, Inkrement und Dekrement ++ --, Arithmetik + - * / %, Vergleiche == != <= >= < >, Bit-Operationen & | ^ << >>. Alle Integer-Typen haben Vorzeichen, deshalb wirken << >> arithmetisch, d.h. >> propagiert das Vorzeichen. Ein neuer Operator >>> verschiebt und propagiert dabei das Vorzeichen nicht. Integer-Operationen erfolgen im Bereich int, und in long nur, wenn wenigstens ein Operand long ist. Eine ArithmeticException erfolgt nur bei Division oder Rest-Bildung mit Null. 26 Berechnung der Wertbereiche — int/Ranges Ranges gibt die Wertbereiche der Integer-Datentypen aus. Ranges demonstriert den Umgang mit Integer-Werten, Bit-Operationen und Umwandlungen. {programs/int/Ranges.java} /** A class demonstrating bit operations to determine integer ranges */ class Ranges { public static void main (String args []) { byteRange(); shortRange(); intRange(); longRange(); } /** uses complement operations */ static void intRange () { System.out.println("int\t" + (~0 >>> 1) + "\t" + (~ (~0 >>> 1))); } /** maximum and minimum long value */ static final long maxLong = ~0L >>> 1, minLong = ~ (~0L >>> 1); static void longRange () { System.out.println("long\t" + maxLong + "\t" + minLong); } /** uses casts and literals */ static void shortRange () { System.out.println("short\t" + (short)077777 + "\t" + (short)0x8000); } /** shifts ones until no further changes occur */ static void byteRange () { byte i, j = 1; do { i = j; j = (byte)(i << 1 | 1); } while (j > i); System.out.print("byte\t" + i); do { i = j; j = (byte)(i << 1); } while (j < i); System.out.println("\t" + i); } } {} erzeugt durch Komplementieren von 0 und Verschieben ohne Propagieren des Vorzeichens ein maximales und durch erneutes Komplementieren ein minimales Bitmuster. + dient zum Verketten von Zeichenketten. Integer-Operanden werden dabei in Text umgewandelt. Explizite Formatierung ist möglich mit java.text . intRange() definiert maxLong und minLong als Klassenvariablen, final erlaubt keine weitere Zuweisung. Zur Initialisierung wird ein long-Literal und daher long-Arithmetik verwendet. static beruht auf int-Literalen, die explizit in short umgewandelt werden. Die folgende Lösung für den minimalen Wert ist in C aber nicht in Java möglich (warum?): shortRange() (short) ~ ((unsigned short) ~0 >> 1) verwendet do-while-Schleifen. byte kann zwar mit int initialisiert werden, aber bei der Zuweisung ist eine explizite Umwandlung nötig. byteRange() 27 Ausnahmebehandlung — int/Try Try dividiert 6 durch die Anzahl der Kommandoargumente. Try demonstriert, wie man eine Exception abfängt . {programs/int/Try.java} /** A class demonstrating an arithmetic exception */ class Try { /** divides 6 by the number of arguments */ public static void main (String args []) { try { System.out.println(6 +"/"+ args.length +" is "+ 6/args.length); } catch(final Exception e) { System.err.println(e.getClass().getName() +": "+ e.getMessage()); e.printStackTrace(); } finally { System.err.println("done"); } } } {} main() erhält die Kommandoargumente (ohne java und den Klassennamen) als konstante Zeichenketten im Vektor args[]. Jeder Vektor hat eine Komponente .length, die die Anzahl der Elemente enthält. kontrolliert einen Block, dem catch-Blocks folgen. Passiert ein Fehler, wird das resultierende Exception-Objekt der ersten catch-Klausel übergeben, die es als Argument empfangen kann. Abschließend wird — mit oder ohne Fehler und falls vorhanden — der finally-Block ausgeführt. Danach geht es nach try weiter. try Auch falls try mit einer Sprunganweisung (break, continue, return) oder infolge einer neuen Exception verlassen wird, findet finally statt, nicht aber die auf try folgende Anweisung. Mit final wird bei lokalen Variablen angezeigt, daß sie nur initialisiert, aber nicht mehr verändert werden. Alles außer lokalen Variablen wird a priori mit Null initialisiert. ist ein Throwable , das abgefangen werden sollte und das dann untersucht werden kann. Hier sieht man etwa folgendes: Exception $ Try java.lang.ArithmeticException: / by zero java.lang.ArithmeticException: / by zero at Try.main(Try.java:6) done 28 Umwandlungen — int/Cvt Cvt wandelt seine dezimalen Argumente in den Radix um, der als erstes, dezimales Argument angegeben ist. Cvt illustriert statische Methoden der Integer-Klasse , mit der auch Integer-Werte als Objekte verpackt werden können. Es gibt auch eine BigInteger-Klasse , mit der beliebig große Zahlen verarbeitet werden können. {programs/int/Cvt.java} /** A class using static methods from the Integer class */ class Cvt { /** converts decimal args[1..] to decimal radix args[0] */ public static void main (String args []) { if (args == null || args.length <= 1) { System.err.println("usage: Cvt radix number ..."); System.exit(1); } try { int radix = Integer.parseInt(args[0]); if (radix<2 || radix>36) throw(new Exception("bad radix")); for (int n = 1; n < args.length; ++ n) { int arg = Integer.parseInt(args[n]); switch (radix) { case 8: if (arg != 0) System.out.print("0"); case 10: break; case 16: System.out.print("0x"); break; default: System.out.print(radix + "#"); } System.out.println(Integer.toString(arg, radix)); } } catch(Exception e) { System.err.println(e.getClass().getName() +": "+ e.getMessage()); System.exit(1); } } } {} 29 Die if-Anweisung stammt aus C; allerdings muß die Bedingung boolean sein . Vektoren wie args[] werden ab Null indiziert — mit IndexOutOfBoundsException . Vereinbarungen können in einem Block beliebig mit Anweisungen gemischt werden. Der Stil ist ähnlich zu C, aber einfacher. Die throw-Anweisung verursacht eine Ausnahme. new erzeugt hier das Exception-Objekt für die nachfolgende catch-Klausel. Bei der for-Schleife kann eine lokale Definition stehen oder es können mehrere Initialisierungen durch Komma getrennt angegeben werden; auch im Inkrement-Teil kann Komma verwendet werden. Sonst gibt es keinen Komma-Operator. Vorsicht: Die lokale Definition gehört zur for-Anweisung als Block, nicht in den Block, in dem die for-Anweisung selbst steht. Die switch-Anweisung wählt mit einem char- oder Integer-Wert eine case-Marke oder default: in einem Block. Der Vergleich erfolgt als int; ein long-Wert muß explizit umgewandelt werden. Wie in C ist break nötig, um eine Alternative zu beenden. entspricht atoi(). Integer.toString() erlaubt Radix 2 bis 36 (und tut sonst nichts!). Beides sind Klassenmethoden; es gibt auch toOctalString() und andere. Integer.parseInt()