Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Java ist auch eine Insel von Christian Ullenboom
Buch: Java ist auch eine Insel (Galileo Computing)
gp Kapitel 11 Datenstrukturen und Algorithmen
gp 11.1 Mit einem Iterator durch die Daten wandern
gp 11.1.1 Die Schnittstellen Enumeration und Iterator
gp 11.1.2 Arrays mit Iteratoren durchlaufen
gp 11.2 Datenstrukturen und die Collection-API
gp 11.2.1 Die Schnittstelle Collection
gp 11.2.2 Das erste Programm mit Container-Klassen
gp 11.2.3 Schnittstellen, die Collection erweitern, und Map
gp 11.2.4 Konkrete Container-Klassen
gp 11.3 Listen
gp 11.3.1 AbstractList
gp 11.3.2 Beispiel mit List-Methoden
gp 11.3.3 ArrayList
gp 11.3.4 asList() und die »echten« Listen
gp 11.3.5 toArray() von Collection verstehen - die Gefahr einer Falle erkennen
gp 11.3.6 Die interne Arbeitsweise von ArrayList und Vector
gp 11.3.7 LinkedList
gp 11.3.8 Queue, die Schlange
gp 11.4 Stack (Kellerspeicher, Stapel)
gp 11.4.1 Die Methoden von Stack
gp 11.4.2 Ein Stack ist ein Vector - aha!
gp 11.5 Die Klasse HashMap und assoziative Speicher
gp 11.5.1 Ein Objekt der Klasse HashMap erzeugen
gp 11.5.2 Einfügen und Abfragen der Datenstruktur
gp 11.5.3 Wichtige Eigenschaften von Assoziativspeichern
gp 11.5.4 Elemente im Assoziativspeicher müssen unveränderbar bleiben
gp 11.5.5 Die Arbeitsweise einer Hash-Tabelle
gp 11.5.6 Aufzählen der Elemente
gp 11.5.7 Der Gleichheitstest und der Hash-Wert einer Hash-Tabelle
gp 11.5.8 Klonen
gp 11.6 Die abstrakte Klasse Dictionary
gp 11.7 Die Properties-Klasse
gp 11.7.1 Über die Klasse Properties
gp 11.7.2 put(), get() und getProperties()
gp 11.7.3 Eigenschaften ausgeben
gp 11.7.4 Systemeigenschaften der Java-Umgebung
gp 11.7.5 Browser-Version abfragen
gp 11.7.6 Properties von der Konsole aus setzen
gp 11.7.7 Windows-typische INI-Dateien
gp 11.8 Algorithmen in Collections
gp 11.8.1 Datenmanipulation: Umdrehen, Füllen, Kopieren
gp 11.8.2 Vergleichen von Objekten mit Comparator und Comparable
gp 11.8.3 Größten und kleinsten Wert einer Collection finden
gp 11.8.4 Sortieren
gp 11.8.5 nCopies()
gp 11.8.6 Singletons
gp 11.8.7 Elemente in der Collection suchen
gp 11.9 Synchronisation der Datenstrukturen
gp 11.10 Typsichere Datenstrukturen
gp 11.11 Die abstrakten Basisklassen für Container
gp 11.11.1 Optionale Methoden
gp 11.12 Die Klasse BitSet für Bitmengen
gp 11.12.1 Ein BitSet anlegen und füllen
gp 11.12.2 Mengenorientierte Operationen
gp 11.12.3 Funktionsübersicht
gp 11.12.4 Primzahlen in einem BitSet verwalten
gp 11.13 Ein Design-Pattern durch Beobachten von Änderungen
gp 11.13.1 Design-Pattern
gp 11.13.2 Das Beobachter-Pattern (Observer/Observable)


Galileo Computing

11.7 Die Properties-Klassedowntop

Unter älteren Windows-Versionen gibt es INI-Dateien, in denen ebenfalls Datenpaare aus Schlüssel und Wert abgelegt sind. Für eine alte Windows-Umgebung ist beispielsweise win.ini eine wichtige Datei, in der Systemeinstellungen gesichert sind.


Beispiel Ein Ausschnitt aus der Datei win.ini
[Desktop]
Wallpaper=(None)
TileWallpaper=1
WallpaperStyle=0
Pattern=(None)
...
[colors]
Scrollbar=224 224 224
Background=0 128 128
ActiveTitle=0 0 128

Es finden sich in der Datei mit einem eindeutigen Schlüsselwort verbundene Zeichenketten. Die INI-Datei kann einfach mit einem beliebigen ASCII-Editor angepasst werden und ist somit leicht für Änderungen zugänglich. In Java gibt es einen ähnlichen Mechanismus. Die Klasse Properties erlaubt, solche Wertepaare aufzubauen und dadurch die Daten aus dem Programmtext herauszuziehen und in eine Art INI-Datei zu legen, die eine Änderung der Werte bequem ohne Neucompilierung möglich macht. Leider kann eine Eigenschaften-Datei nicht segmentiert werden. Hierarchisch benannte Eigenschaften wie Desktop. Wallpaper sind eine interessante Alternative, doch tauchen sie dann quer gewürfelt in der Datei auf, da ein Assoziativspeicher keine Sortierung besitzt.


Galileo Computing

11.7.1 Über die Klasse Propertiesdowntop

Die Properties-Klasse ist eine Erweiterung von Hashtable, da die Speicherung der Einstellungsdaten in dieser Datenstruktur erfolgt. Ein Properties-Objekt erweitert die Hash-Tabelle um die Möglichkeit, die Schlüssel-Werte-Paare in einem festgelegten Format aus einer Textdatei beziehungsweise einem Datenstrom zu laden und wieder zu speichern. Außerdem kommt noch eine Hierarchie von Hash-Tabellen hinzu; jedes Properties-Exemplar hat ein Eltern-Properties-Objekt, das gegebenenfalls automatisch durchsucht wird. Und gerade weil Hashtable erweitert wird, sind auch alle Methoden der Klasse Hashtable auf ein Properties-Objekt anwendbar. Das macht nicht für alle Methoden Sinn und ist auch nicht in jedem Fall problemlos. Dass Properties eine Unterklasse von Hashtable ist, ist ähnlich fragwürdig wie die Vererbungsbeziehung Stack/Vector.


Beispiel Das nachfolgende Programm erzeugt zwei Properties-Objekte. Eine davon ist eine Standardliste und die andere soll eine benutzerdefinierte sein, die anfänglich alle Einstellungen von der Standardliste übernimmt. Dieses Übernehmen ist durch einen speziellen Konstruktor möglich, denn beim Erzeugen der benutzerdefinierten Liste wird eine andere Liste einfach im Konstruktor übergeben.

Listing 11.7 TestProperties.java

import java.util.Properties;
class TestProperties
{
  public static void main( String args[] )
  {
    Properties defaultProperties = new Properties(),
               userProperties = new Properties(defaultProperties);
    defaultProperties.setProperty( "User", "Standard" );
    defaultProperties.setProperty( "Version", "" + 0.02f );
    userProperties.setProperty( "User", "Ulli Schnulli" );
    userProperties.setProperty( "MagCleverUndSmart", "" + true );
    System.out.println( "Default Properties:" );
    defaultProperties.list( System.out );
    System.out.println( "\nUser Properties:" );
    userProperties.list( System.out );
    System.out.println( "Property 'User' is '" +
                        userProperties.getProperty("User") + "'" );
    }
}

Testen wir das Programm, so fällt ein Zusammenhang besonders auf: Obwohl wir zunächst das Default- und User-Objekt erzeugen, werden die später zum Default-Objekt hinzugefügten Daten an das User-Objekt weitergereicht. Nachträglich dem Default-Objekt zugeordnete Werte kommen also auch zum Aufrufer zurück. Die Implementierung zeigt: Zuerst durchsucht ein Property-Exemplar die eigene, in ihm enthaltene Hash-Tabelle. Liefert diese keinen Eintrag oder keinen Wert vom Typ String, so wird das im Konstruktoraufruf angegebene Property-Objekt durchsucht. Auf diese Weise lassen sich mehrstufige Hierarchien von Property-Verzeichnissen konstruieren. Damit ergibt sich die Ausgabe:

Default Properties:
-- listing properties --
Version=0.02
User=Standard
User Properties:
-- listing properties --
MagCleverUndSmart=true
Version=0.02
User=Ulli Schnulli
Property 'User' is 'Ulli Schnulli'

Galileo Computing

11.7.2 put(), get() und getProperties()downtop

Ein weiterer Augenmerk ist auf die put()-Funktion zu legen. Sie gibt es in der Klasse Properties nicht, denn put() wird von Hashtable geerbt. Wir sollten sie jedoch nicht verwenden, da es über sie möglich ist, Objekte einzufügen, die nicht vom Typ String sind. Properties von Hashtable abzuleiten ist übrigens ein genauso fragwürdiges Beispiel für den Einsatz von Vererbung (wie Stack als Unterklasse von Vector).

Das gleiche Argument könnte für get() gelten, doch zwei Dinge sprechen dagegen: Zunächst einmal, dass wir beim get() aus einem Hashtable-Objekt immer ein Object-Objekt bekommen und daher meistens einen Cast brauchen, und zweitens durchsucht diese Methode lediglich den Inhalt des angesprochenen Properties-Exemplars. getProperties() arbeitet da etwas anders. Nicht nur, dass der Rückgabewert automatisch ein String ist, sondern auch, dass nachgeschachtelte Properties-Objekte mit durchsucht werden, die zum Beispiel Standardwerte speichern.


class java.util.Properties
extends Hashtable

gp Properties()
Erzeugt ein leeres Properties-Objekt ohne Schlüssel und Werte.
gp Properties( Properties defaults )
Erzeugt ein leeres Properties-Objekt, das bei Anfragen auch auf die Einträge in dem übergebenen Properties-Objekt zurückgreift.
gp String getProperty( String key )
Sucht in den Properties nach der Zeichenkette key als Schlüssel und liefert den zugehörigen Wert. Durchsucht auch nachgeschaltete Properties-Objekte.
gp String getProperty( String key, String default )
Sucht in den Properties nach der Zeichenkette key als Schlüssel und liefert den zugehörigen Wert. Ist der Schlüssel nicht vorhanden, wird der String default zurückgegeben.
gp Object setProperty( String key, String value )
Trägt Schlüssel und Wert im Properties-Exemplar ein. Existiert der Schlüssel schon, wird er überschrieben. Mitunter verdeckt der Schlüssel den Wert der Property in der übergeordneten Property.

Galileo Computing

11.7.3 Eigenschaften ausgebendowntop

Eine kleine Hilfe zum Testen bietet die Bibliothek durch eine list()-Methode. Sie wandert einfach durch die Daten eines Properties-Exemplars und gibt sie auf einem PrintStream oder PrintWriter aus. Das sind Datenströme, denen wir uns näher im Eingabe- und Ausgabekapitel widmen wollen. Eine Ausgabe auf dem Bildschirm erhalten wir mit list(System.out).

Die Paare folgen einer Kopfzeile

-- listing properties --

und haben die Form:

Schlüssel=Wert

Umfasst der Wert mehr als 40 Zeichen, wird die Ausgabe mit »...« abgekürzt.


class java.util.Properties
extends Hashtable

gp void list( PrintStream out )
Listet die Properties auf dem PrintStream aus.
gp void list( PrintWriter out )
Listet die Propierties auf dem PrintWriter aus.

Galileo Computing

11.7.4 Systemeigenschaften der Java-Umgebungdowntop

In einem weiteren Beispiel erzeugen wir ein Properties-Objekt, welches direkt die System-Java-Properties widerspiegelt. Nach dem Hinzufügen eines Eintrags schreiben wir diese Werte in eine Datei, lesen sie wieder und geben sie mit der list()-Methode aus. Eine umfangreiche Liste von Systemeigenschaften bietet die Web-Seite http://www.tolstoy.com/samizdat/sysprops.html.

Listing 11.8 SaveProperties.java

import java.io.*;
import java.util.*;
class SaveProperties
{
  public static void main( String args[] )
  {
   String filename = "properties.txt";
    try
    {
      FileOutputStream propOutFile =
         new FileOutputStream( filename );
      Properties p1 = new Properties( System.getProperties() );
      p1.setProperty( "MeinNameIst", "Forest Gump" );
      p1.store( propOutFile, "Eine Insel mit zwei Bergen" );
      FileInputStream propInFile = new FileInputStream( filename );
      Properties p2 = new Properties();
      p2.load( propInFile );
      p2.list( System.out );
     }
     catch ( FileNotFoundException e ) {
       System.err.println( "Can't find " + filename );
     }
     catch ( IOException e ) {
       System.err.println( "I/O failed." );
     }
  }
}

class java.util.Properties
extends Hashtable

gp void load( InputStream inStream )
Lädt eine Properties-Liste aus einem Eingabestrom.
gp void store( OutputStream out, String header )
Speichert die Properties-Liste mit Hilfe des Ausgabestroms ab. Am Kopf der Datei wird eine Kennung geschrieben, die im zweiten Argument steht. Die Kennung darf auch null sein.
gp void Enumeration propertyNames()
Liefert eine Enumeration von allen Schlüsseln in der Property-Liste inklusive der Standardwerte aus nachgeschalteten Properties.

Galileo Computing

11.7.5 Browser-Version abfragendowntop

Eine besondere Eigenschaft bezeichnet die Zeichenkette browser.version. Ob es sich bei dem Browser um einen Internet Explorer oder um einen Netscape Communicator handelt, können wir aus der Variablen java.vendor auslesen.

String prop = System.getProperty( "java.vendor" );
boolean ie = prop.indexOf( "Microsoft Corp." ) >= 0;

Bei der Anweisung System.getProperty(key) ist das Properties-Objekt gut versteckt. In einer etwas längeren Schreibweise ist das etwa:

Properties prop = System.getProperties();
String s = prop.getProperty( "property" );

Galileo Computing

11.7.6 Properties von der Konsole aus setzendowntop

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 11.9 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. Im Fall von Wahrheitswerten gibt es die Sonderfunktion getBoolean() in der Klasse Boolean, die aus der Eigenschaften-Liste der Klasse System eine Eigenschaft mit dem angegebenen Namen heraussucht. Es erstaunt, diese Funktion in der Wrapper-Klasse Boolean anzutreffen. Der einzige Vorteil gegenüber der Lösung mit der valueOf()-Methode ist, dass die Groß-/Kleinschreibung beim Wert keine Rolle spielt. Dies erkaufen wir mit dem Nachteil, dass wir bei einem false nicht unterscheiden können, ob es die Eigenschaft nicht gibt, oder ob sie mit dem Wert false belegt ist.


Galileo Computing

11.7.7 Windows-typische INI-Dateientoptop

Für die INI-Dateien mit Segmenten gibt es in Java keine Unterstützung, doch die Entwicklergemeinde hat die Lücke schnell gefüllt. So lässt sich von Aresch Yavari unter http://www.geocities.com/Area51/9851/INIFiles.html eine Unterstützung für die Windows-INI-Files beziehen.





Copyright (c) Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de