Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

 << zurück
Java ist auch eine Insel von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 5
Java ist auch eine Insel

Java ist auch eine Insel
5., akt. und erw. Auflage
1454 S., mit CD, 49,90 Euro
Galileo Computing
ISBN 3-89842-747-1
gp Kapitel 11 Datenstrukturen und Algorithmen
  gp 11.1 Datenstrukturen und die Collection-API
    gp 11.1.1 Die Schnittstelle Collection
    gp 11.1.2 Das erste Programm mit Container-Klassen
    gp 11.1.3 Die Schnittstelle Iterable und das erweiterte for
    gp 11.1.4 Generische Datentypen in der Collection-API
    gp 11.1.5 Generischer Typ bei Iterable und konkreter Typ beim erweiterten for
    gp 11.1.6 Schnittstellen, die Collection erweitern, und Map
    gp 11.1.7 Konkrete Container-Klassen
  gp 11.2 Mit einem Iterator durch die Daten wandern
    gp 11.2.1 Die Schnittstellen Enumeration und Iterator
    gp 11.2.2 Der typisierte Iterator
  gp 11.3 Listen
    gp 11.3.1 Die Schnittstelle List
    gp 11.3.2 Beispiel mit List-Methoden
    gp 11.3.3 ArrayList
    gp 11.3.4 Arrays.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.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 Queues (Schlangen)
    gp 11.5.1 Blockierende Queues und Prioritätswarteschlangen
  gp 11.6 Assoziative Speicher HashMap und TreeMap
    gp 11.6.1 Ein Objekt der Klasse HashMap erzeugen
    gp 11.6.2 Einfügen und Abfragen der Datenstruktur
    gp 11.6.3 Wichtige Eigenschaften von Assoziativspeichern
    gp 11.6.4 Elemente im Assoziativspeicher müssen unveränderbar bleiben
    gp 11.6.5 Aufzählen der Elemente
    gp 11.6.6 Der Gleichheitstest, Hash-Wert und Klon einer Hash-Tabelle
    gp 11.6.7 Die Arbeitsweise einer Hash-Tabelle
  gp 11.7 Die Properties-Klasse
    gp 11.7.1 Properties setzen und lesen
    gp 11.7.2 Properties verketten
    gp 11.7.3 Eigenschaften ausgeben
    gp 11.7.4 Hierarchische Eigenschaften
    gp 11.7.5 Properties speichern
    gp 11.7.6 Über die Beziehung Properties und Hashtable
  gp 11.8 Mengen (Sets)
    gp 11.8.1 HashSet
    gp 11.8.2 TreeSet – die Menge durch Bäume
    gp 11.8.3 LinkedHashSet
  gp 11.9 Algorithmen in Collections
    gp 11.9.1 Datenmanipulation: Umdrehen, Füllen, Kopieren
    gp 11.9.2 Vergleichen von Objekten mit Comparator und Comparable
    gp 11.9.3 Größten und kleinsten Wert einer Collection finden
    gp 11.9.4 Sortieren
    gp 11.9.5 Elemente in der Collection suchen
    gp 11.9.6 Nicht-änderbare Datenstrukturen
    gp 11.9.7 nCopies()
    gp 11.9.8 Singletons
  gp 11.10 Synchronisation der Datenstrukturen
    gp 11.10.1 Lock-Free-Algorithmen aus java.util.concurrent
    gp 11.10.2 Wrapper zur Synchronisation
    gp 11.10.3 CopyOnWriteArrayList und CopyOnWriteArraySet
  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-Klasse  downtop

Die Klasse Properties ist eine Sonderform der Assoziativspeicher, bei der Schlüssel/Wertepaare immer vom Typ Strings sind. Sie können später in einer Datei gespeichert und wieder ausgelesen werden. Auf diese Weise lassen sich zum Beispiel Zeichenketten aus dem Programmtext ziehen und externalisieren, sodass die Werte auch ohne Neuübersetzung bequem verändert werden können.


Galileo Computing

11.7.1 Properties setzen und lesen  downtop

Um ein Properties-Objekt zu füllen, wird die Funktion setProperty() eingesetzt. Die Argumente sind zwei Zeichenketten, der Schlüssel und der Wert. Um später wieder an den Schlüssel zu kommen, wird getProperty() mit dem Schlüssel aufgerufen und liefert dann – wenn beide Zeichenketten vorher verbunden wurden – den Wert.

Properties props = new Properties();
props.setProperty( "User""King Karl" );
props.setProperty( "Version""" + 0.02 );
System.out.println( props.getProperty("User") );      // King Karl
System.out.println( props.getProperty("Passwort") );  // null

Galileo Computing

11.7.2 Properties verketten  downtop

Properties-Objekte lassen sich hierarchisch verbinden, sodass im Fall einer erfolglosen Suche nach einem Schlüssel das Properties-Objekt die Anfrage an ein übergeordnetes Properties-Objekt weiterleitet; das Eltern-Properties-Objekt wird einfach im Konstruktor übergeben.


Beispiel   Das nachfolgende Programm erzeugt zwei Properties-Objekte. Eines davon ist eine Standardliste und das andere soll eine benutzerdefinierte sein, die anfänglich alle Einstellungen der Standardliste übernimmt.

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 die Weiterleitung 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. Über list() 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'

class java.util.  Properties
  extends Hashtable<Object,Object>

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 ausgeben  downtop

Die list()-Methode wandert durch die Daten eines Properties-Exemplars und schreibt sie in einen PrintStream oder PrintWriter. 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). Schlüssel und Werte werden von einem Gleichheitszeichen getrennt. Die Ausgabe über list() ist gekürzt, denn ist ein Wert länger als 40 Zeichen, wird er abgekürzt. Den Paaren geht eine Kopfzeile der Art -- listing properties -- voran. Es ist wichtig zu verstehen, dass durch die Art der Speicherung (ein Assoziativspeicher auf Basis des Hashings) die Ausgabe unsortiert erfolgt.


class java.util.  Properties
  extends Hashtable<Object,Object>

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

Galileo Computing

11.7.4 Hierarchische Eigenschaften  downtop

Leider kann eine Eigenschaften-Datei nicht segmentiert werden, wie etwa alte Windows INI-Dateien dies machen. Die Alternative besteht darin, hierarchisch benannte Eigenschaften zu erzeugen, indem eine Zeichenkette vor jeden Schlüssel gesetzt wird. Um zum Beispiel einen Schlüssel User einmal unter Private und einmal unter Public zu halten, lässt sich die Eigenschaft Private.User und Public.User einsetzen. Doch leider tauchen sie dann gespeichert quer gewürfelt in der Datei auf, weil ein Assoziativspeicher keine Sortierung besitzt.


Galileo Computing

11.7.5 Properties speichern  downtop

Während die list()-Funktion nur für Testausgaben gedacht ist, dient store() zum Speichern und load() zum Laden eines Properties-Objektes in einer ASCII-Datei, die Schlüssel und Werte mit einem Gleichheitszeichen trennt.

Das folgende Beispiel initialisiert ein Properties-Objekt mit den Systemeigenschaften und fügt dann einen Wert hinzu. Anschließend werden die Daten persistent gemacht, wieder gelesen und mit der list()-Methode auf dem Bildschirm ausgegeben.

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<Object,Object>

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 null sein.
gp  void Enumeration<?> propertyNames() Liefert eine Enumeration von allen Schlüsseln in der Property-Liste inklusive der Standardwerte aus nachgeschalteten Properties.

Properties im XML-Format speichern

Seit Java 5 können die Properties auch im XML-Format gespeichert und geladen werden. Zum Speichern dient die Funktion storeXML() und zum Laden loadFromXML(). Die XML-Dateien haben ein spezielles Format, wie es ein Einzeiler wie System.getProperties(). storeToXML(System.out, ""); zeigt.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment></comment>
<entry key="java.runtime.name">Java(TM) 2 Runtime EnvironmentStandard Edition</entry>
<entry key="java.vm.vendor">Sun Microsystems Inc.</entry>
<entry key="java.vendor.url">http://java.sun.com/</entry>
<entry key="path.separator">;</entry>
...
<entry key="sun.desktop">windows</entry>
<entry key="sun.cpu.isalist">pentium i486 i386</entry>
</properties>

Die Methode loadFormXML() liest aus einem InputStream und löst im Fall eines fehlerhaften Dateiformats eine InvalidPropertiesFormatException aus. Beim Speichern kann so ein Fehler natürlich nicht auftreten. Und genauso, wie bei store() ein OutputStream mit einem Kommentar gespeichert wird, tut das auch storeToXML(). Die Funktion ist mit einem zusätzlichen Parameter überladen, der eine XML-Kodierung erlaubt. Ist der Wert nicht gesetzt, so ist die Standardkodierung UTF-8.


Galileo Computing

11.7.6 Über die Beziehung Properties und Hashtable  toptop

Die Properties-Klasse ist eine Erweiterung von Hashtable, weil 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. Doch gerade weil Hashtable erweitert wird, sind auch alle Methoden der Klasse Hashtable auf ein Properties-Objekt anwendbar. Das ergibt 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 als Unterklasse von Vector. So ist ein Augenmerk auf die put()-Funktion zu legen. Sie gibt es in der Klasse Properties nicht, denn put() wird von Hashtable geerbt. Wir sollten sie auch nicht verwenden, da es über sie möglich ist, Objekte einzufügen, die nicht vom Typ String sind. Das gleiche Argument könnte für get() gelten, doch sprechen zwei Dinge dagegen: Zum einen, dass wir beim get() aus einem Hashtable-Objekt immer ein Object-Objekt bekommen und daher meistens eine Typanpassung benötigen, und zum anderen 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 nachgeschaltete Properties-Objekte mit durchsucht werden, die zum Beispiel Standardwerte speichern.

 << zurück




Copyright © Galileo Press GmbH 2005
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, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de