8.4 Die Utility-Klasse System
 
8.4.1 Systemeigenschaften der Java-Umgebung
 
Die Java-Umgebung verwaltet Systemeigenschaften wie Pfadtrenner oder Version der virtuellen Maschine in einem java.util.Properties-Objekt. Die statische Funktion System.getProperties() erfragt diese Systemeigenschaften und liefert das gefüllte Properties-Objekt zurück. Zum Erfragen einzelner Eigenschaften ist das Properties-Objekt aber nicht unbedingt nötig: System.getProperty() erfragt direkt eine Eigenschaft.
Beispiel Gib den Namen des Betriebssystems aus.
System.out.println( System.getProperty("os.name") );
Gib alle Systemeigenschaften auf dem Bildschirm aus.
System.getProperties().list( System.out );
|
Eine Liste der Standard-Systemeigenschaften bietet die API-Dokumentation, und die Web-Seite http://java-tutor.com/go/sysprops sammelt für unterschiedliche Laufzeitumgebungen Belegungen.
final class java.lang. System
|
|
static String getProperty( String key )
Gibt die Belegung einer Systemeigenschaft. Ist der Schlüssel null oder leer, gibt es eine NullPointerException bzw. eine IllegalArgumentException. |
|
static String getProperty( String key, String def )
Gibt die Belegung einer Systemeigenschaft. Ist sie nicht vorhanden, liefert die Funktion die Zeichenkette def, den Default-Wert. Für die Ausnahmen gilt das Gleiche wie bei getProperty(String). |
|
static String setProperty( String key, String value )
Belegung der Systemeigenschaft neu. Es wird die alte Belegung (oder null, falls es keine alte Belegung gab) zurückgegeben. |
|
static String clearProperty( String key )
Löscht eine Systemeigenschaft aus der Liste. Es wird die alte Belegung (oder null, falls es keine alte Belegung gab) zurückgegeben. |
|
static Properties getProperties()
Liefert ein mit den aktuellen Systembelegungen gefülltes Properties-Objekt. |
8.4.2 line.separator
 
Um nach dem Ende einer Zeile zum Anfang der nächsten zu kommen, wird ein Zeilenumbruch (engl. new line) eingefügt. Das Zeichen für den Zeilenumbruch muss kein einzelnes sein, es können auch mehrere Zeichen nötig sein. Zum Leidwesen der Programmierer unterscheidet sich die Anzahl der Zeichen für den Zeilenumbruch auf den bekannten Architekturen:
|
Unix: Line Feed (Zeilenvorschub) |
|
Macintosh: Carriage Return (Wagenrücklauf) |
|
Windows: beide Zeichen (Carriage Return und Linefeed) |
Der Steuercode für Carriage Return (kurz CR) ist 13 (0x0D), der für Line Feed (kurz LF) ist 10 (0x0A). Java vergibt obendrein eigene Escape-Sequenzen für diese Zeichen: \r für Carriage Return und \n für Line Feed. (Die Sequenz \f für ein Form Feed – Seitenvorschub – spielt bei den Zeilenumbrüchen keine Rolle.)
Um sich nicht in eine Abhängigkeit eines Betriebssystems zu begeben, sollte der Zeilenumbruch vom System erfragt werden. Hierzu gibt es eine Property: line.separator. Unter Windows ergibt sich folgendes Bild:
System.out.println( System.getProperty("os.name") ); // Windows 2000
String lineSep = System.getProperty( "line.separator" );
System.out.println( lineSep.length() ); // 2
System.out.println( Integer.toHexString(lineSep.charAt(0)) ); // d
if ( lineSep.length() > 1 )
System.out.println( Integer.toHexString(lineSep.charAt(1)) ); // a
Mit einem println() oder »%n« in format() beziehungsweise printf() haben wir auch keine Probleme.
8.4.3 Browser-Version abfragen
 
Nützlich für Applets sind die Eigenschaften browser.version und java.vendor. Letzteres identifiziert den Browser, und so lässt sich in Erfahrung bringen, ob der Browser ein Internet Explorer oder Netscape Communicator ist.
String prop = System.getProperty( "java.vendor" );
boolean isIe = prop.indexOf( "Microsoft Corp." ) >= 0;
8.4.4 Property von der Konsole aus setzen
 
Eigenschaften lassen sich auch bei Programmstart von der Konsole aus setzen. Dies ist praktisch für eine Eigenschaft, die beispielsweise das Verhalten des Programms steuert oder das Programm konfiguriert. In der Kommandozeile werden mit -D der Name der Eigenschaft und ihr Wert angegeben. Viele Entwicklungsumgebungen erlauben es, diese in einem Fenster zu setzen. Die Informationen tauchen nicht bei der Argument-Liste in der main()-Methode auf, da sie vor dem Namen der Klasse stehen und bereits von der Java-Laufzeitumgebung verarbeitet werden.
Um die Eigenschaften auszulesen, gibt es zwei Möglichkeiten. Eine davon ist überraschend.
Listing 8.7
SetProperty.java
class SetProperty
{
static public void main( String[] args )
{
boolean debug = false;
String prop = System.getProperty( "DEBUG" );
// Erster Weg
if ( prop != null )
debug = Boolean.valueOf(prop).booleanValue();
if ( debug )
System.out.println( "Wir dürfen debuggen" );
// Zweiter Weg
System.out.println( Boolean.getBoolean("DEBUG") );
}
}
Auf der Konsole folgt die Ausgabe:
$ java -DDEBUG=true SetProperty
Wir dürfen debuggen
true
Wir bekommen über getProperty() einen String zurück, der den Wert anzeigt. Falls es überhaupt keine Eigenschaft mit diesem Namen gibt, erhalten wir stattdessen null. So wissen wir auch, ob dieser Wert überhaupt gesetzt wurde.
Für die Wahrheitswerte gibt es die statische Funktion getBoolean() in der Klasse Boolean, die aus den System-Properties eine Eigenschaft mit dem angegebenen Namen heraussucht.
public static boolean getBoolean( String name ) {
return toBoolean( System.getProperty(name) );
}
Es erstaunt, diese Funktion in der Wrapper-Klasse Boolean anzutreffen, weil dies nichts mit den Wrapper-Objekten zu tun hat. Gegenüber einer eigenen, direkten System-Anfrage hat getBoolean() auch den Nachteil, dass wir bei der Rückgabe false nicht unterscheiden können, ob es die Eigenschaft nicht gibt, oder ob die Eigenschaft mit dem Wert false belegt ist.
final class java.lang. Boolean
implements Serializable, Comparable<Boolean>
|
|
static boolean getBoolean( String propName )
Liest eine Systemeigenschaft aus. |
8.4.5 Umgebungsvariablen des Betriebssystems
 
Fast jedes Betriebssystem nutzt das Konzept der Umgebungsvariablen; bekannt ist etwa PATH für den Suchpfad für Applikationen unter Windows und unter Unix. Die von Java mittels System.getProperties()eingeführten Eigenschaften unterscheiden sich grundlegend von den System-Umgebungsvariablen und tauchen daher in der Liste nicht auf.
Seit Java 5 ist es möglich, auf diese System-Umgebungsvariablen zuzugreifen. Dazu dient die statische Funktion getenv() von System, wo auch getProperties() zu finden ist. Sie liefert eine Menge von <String, String>-Paaren.
Tabelle 8.4
Auswahl einiger unter Windows verfügbaren Umgebungsvariablen
Name der Variablen
|
Beschreibung
|
Beispiel
|
COMPUTERNAME
|
Name des Computers
|
MOE
|
HOMEDRIVE
|
Laufwerksbuchstabe vom Benutzerverzeichnis
|
C
|
HOMEPATH
|
Pfad des Benutzerverzeichnisses
|
\Dokumente und Einstellungen\Christian Ullenboom
|
OS
|
Name des Betriebssystems
|
Windows_NT
|
PATH
|
Suchpfad
|
C:\WINDOWS\system32;C:\WINDOWS
|
PATHEXT
|
Dateiendungen, die für ausführbare Programme stehen
|
.COM;.EXE;.BAT;.CMD;.WSH
|
SYSTEMDRIVE
|
Laufwerksbuchstabe des Betriebssystems
|
C
|
TEMP und auch TMP
|
Temporäres Verzeichnis
|
C:\DOKUME~1\CHRIST~1\LOKALE~1\Temp
|
USERDOMAIN
|
Domäne des Benutzers
|
MOE
|
USERNAME
|
Name des Nutzers
|
Christian Ullenboom
|
USERPROFILE
|
Profilverzeichnis
|
C:\Dokumente und Einstellungen\Christian Ullenboom
|
WINDIR
|
Verzeichnis des Betriebssystems
|
C:\WINDOWS
|
Einige der Variablen sind auch über die System-Properties zu erreichen.
Um auf eine spezielle Umgebungsvariable zuzugreifen, lässt sich getenv(String) nutzen, etwa um den Suchpfad herauszufinden: System.getenv("path");
Beispiel Gib die Umgebungsvariablen des Systems aus. Um die Ausgabe etwas übersichtlicher zu gestalten, ist bei der Aufzählung jedes Komma durch ein Zeilenvorschubzeichen ersetzt.
Map<String,String> map = System.getenv();
System.out.println( map.toString().replace(’,’, ’\n’) );
|
8.4.6 Einfache Zeitmessung und Profiling
 
Neben den komfortablen Klassen zum Verwalten von Datumswerten gibt es mit zwei Funktionen einfache Wege, Zeiten für Programmabschnitte zu messen:
final class java.lang. System
|
|
static long currentTimeMillis()
Gibt die seit dem 1.1.1970 vergangenen Millisekunden zurück. |
|
static long nanoTime()
Liefert vom genauesten System-Zeitgeber die Zeit. Sie hat keinen Bezugpunkt zu irgendeinem Datum; vom 1.1.1970 sind so viele Nanosekunden vergangen, wie sie gar nicht in den long passen würden. |
Die Differenz zweier Zeitwerte kann zur groben Abschätzung von Ausführungszeiten für Programme dienen.
Listing 8.8
Profiling.java
import java.util.concurrent.TimeUnit;
class Profiling
{
static long[] measure()
{
int MAX = 1000;
String string = "Aber Angie, Angie, ist es nicht an der Zeit, Goodbye zu sagen? " +
"Ohne Liebe in unseren Seelen und ohne Geld in unseren Mänteln. " +
"Du kannst nicht sagen, dass wir zufrieden sind.";
int number = 123;
double nullnummer = 0.0;
// StringBuffer(size) und append() zur Konkatenation
long time1 = System.nanoTime();
StringBuilder sb1 = new StringBuilder( MAX * (string.length() + 6) );
for ( int i = MAX; i-- > 0; )
sb1.append( string ).append( number ).append( nullnummer );
sb1.toString();
time1 = TimeUnit.NANOSECONDS.toMillis( System.nanoTime() – time1 );
// StringBuffer und append() zur Konkatenation
long time2 = System.nanoTime();
StringBuilder sb2 = new StringBuilder();
for ( int i = MAX; i-- > 0; )
sb2.append( string ).append( number ).append( nullnummer );
sb2.toString();
time2 = TimeUnit.NANOSECONDS.toMillis( System.nanoTime() – time2 );
// + zur Konkatenation
long time3 = System.nanoTime();
String t = "";
for ( int i = MAX; i-- > 0; )
t += string + number + nullnummer;
time3 = TimeUnit.NANOSECONDS.toMillis( System.nanoTime() – time3 );
return new long[] { time1, time2, time3 };
}
public static void main( String[] args )
{
measure(); measure();
long[] durations = measure();
System.out.printf( "sb(size), append(): %d ms%n", durations[0] ); // sb(size), append(): 2 ms
System.out.printf( "sb(), append() : %d ms%n", durations[1] ); // sb(), append() : 21 ms
System.out.printf( "t+= : %d ms%n", durations[2] ); // t+= : 10661 ms
}
}
Wird das Programm gestartet, so bekomme ich auf meinem Rechner (AMD Athlon 2,6+, Java SE 5) die nachstehende Ausgabe:
sb(size), append(): 2 ms
sb(), append() : 21 ms
t+= : 10661 ms
Das Ergebnis: Bei großen Anhänge-Operationen ist es sinnvoll, einen passend in der Größe initialisierten StringBuilder zu benutzen. Über das + entstehen viele temporäre Objekte, was teuer kommt.
Wo im Programm überhaupt Taktzyklen verbraten werden, zeigt ein Profiler. An diesen Stellen kann dann mit der Optimierung begonnen werden. Eclipse sieht mit dem TPTP (http://www.eclipse.org/tptp/) eine solche Messumgebung vor.
|