Inhalt |
|
|
Programmeinstellungen lassen sich am leichtesten als Zeichenketten in Dateien speichern. Solche Einstellungen betreffen etwa Flags, die den Programmablauf steuern. Es wird hier zunächst angenommen, dass die Einstellungen vom Benutzer geändert werden können. Diese Dateien werden daher nicht als Ressourcen behandelt.
Will man Einstellungen einlesen, die nicht änderbare Ressourcen sind, so kann man natürlich auf diese Dateien wie schon beschrieben zugreifen. Bei Menütexten oder auszugebenden Meldungen sollte man allerdings erwägen, die Internationalisierungstools zu verwenden, die weiter unten beschrieben werden.
Zunächst werden Einstellungen in Instanzen von Properties gespeichert. Dieser Datentyp ist ein Kind von Hashtable. Es existieren allerdings Funktionen zum Lesen und Schreiben auf Streams. Property-Enthalten die Properties zeilenweise wie folgt
Test=true
Dann stehen links vom Gleichheitszeichen die Schlüssel und rechts die Werte der Ressourcen. Das folgende Programm verwendet eine Datei test.properties vom Home-Verzeichnes des Benutzers.
import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Properties; public class Test { public static void main (String args[]) { new Test(); } public Test () { Properties P = new Properties(); String filename = System.getProperty("user.home") + "/test.properties"; try { // Lies Properties ein: FileInputStream in = new FileInputStream(filename); P.load(in); in.close(); } catch (Exception e) { System.out.println(e); } try { // Drucke einige Properties: System.out.println(P.getProperty("Tes")); System.out.println(P.getProperty("Test")); System.out.println(P.getProperty("Test", "no value")); System.out.println(toBoolean(P.getProperty("Test", "false"))); // Fuege eine Property hinzu P.put("Test", "true"); // Speichere die Properties wieder ab: FileOutputStream out = new FileOutputStream(filename); P.store(out, "Test Properties"); out.close(); } catch (Exception e) { System.out.println(e); } } public static boolean toBoolean (String s) // Intepretiere true oder false { return s.equals("true"); } }
Dieses Programm sollte man zweimal laufen lassen. Beim ersten Mal existiert die Datei test.properties im Homeverzeichnis des Benutzers noch nicht. Daher wird folgendes ausgegeben.
java.io.FileNotFoundException: C:\Users\reneg\test.properties (Das System kann die angegebene Datei nicht finden) null null no value false
Nicht existierende Properties haben den Wert null. Man kann aber einen Default-Wert angeben. Beim zweiten Durchlauf existiert die Datei.
#Test Properties #Sat Aug 19 09:30:15 CEST 2023 Test=true
Es wird nun folgendes ausgegeben.
null true true true
Einige Properties werden vom System vorgegeben und sind mit Hilfe der System-Klasse erreichbar. Das folgende Programm listet alle diese System-Properties auf. Es zeigt außerdem, wie man eine Enumeration aller Keys in einer HashTable bekommt.
import java.util.Enumeration; import java.util.Properties; public class Test { public static void main (String args[]) { Properties P = System.getProperties(); Enumeration<Object> e = P.keys(); while (e.hasMoreElements()) { String key = (String) e.nextElement(); String value = (String) P.get(key); System.out.println(key + "=" + value); } } }
Die Anfang der Ausgabe dieses Programm auf meinem System ist der folgende.
java.specification.version=20 sun.cpu.isalist=amd64 sun.jnu.encoding=Cp1252 java.vm.vendor=Oracle Corporation sun.arch.data.model=64 user.variant= java.vendor.url=https://java.oracle.com/ java.vm.specification.version=20 os.name=Windows 11 ...
Einige dieser Properties sind sehr gut für Applikationen verwendbar. Z.B. lässt sich die verwendete Java-Version abfragen. An anderer Stelle verwenden wir file.separator und user.home verwendet.
Java-Programme sollen leicht auf jedem Rechner der Welt einsetzbar sein. Bei der Ein- und Ausgabe von Texten haben wir schon die Verwendung von Datei-Encoding kennengelernt. Nun gibt es aber weit mehr nationale Einstellungen, wie Zahlenformate, Datum usw. Außerdem soll ein Programm Menütexte und Fehlermeldungen internationalisieren.
Zu diesem Zweck verwendet Java die Klasse Locale. Es gibt aber dort Konstanten für diverse Lände, die man direkt zur initialisierung des von NumberFormat verwenden kann.
Der eingestellte Sprachraum ist nun dafür verantwortlich, wie etwa Zahlen formatiert werden. Die Klasse, die Zahlen formatiert, ist NumberFormat. Man kann nicht direkt eine Instanz dieser Klasse anlegen, sondern benötigt dazu deren statische Methode getInstance() (und Vewandte). Mit Hilfe einer Instanz (die auch mit einem anderen Sprachraum initialisiert werden kann), kann man Zahlen lokal formatieren. Als Beispiel vergleichen wir englische und deutsche Ausgaben.
import java.text.NumberFormat; import java.util.Locale; public class Test { public static void main (String args[]) { // lokale Ausgabe (hier deutsch) NumberFormat numberformat = NumberFormat.getInstance(); System.out.println(numberformat.format(Math.PI)); numberformat.setMaximumFractionDigits(16); System.out.println(numberformat.format(Math.PI)); numberformat.setGroupingUsed(true); // Gruppiert Dreiergruppen von Zahlen System.out.println(numberformat.format(1000000000.01)); // englische Ausgabe (US Format): numberformat = NumberFormat.getInstance(Locale.ENGLISH); System.out.println(numberformat.format(Math.PI)); numberformat.setMaximumFractionDigits(16); System.out.println(numberformat.format(Math.PI)); numberformat.setGroupingUsed(true); System.out.println(numberformat.format(1000000000.01)); } }
Die Ausgaben unterscheiden sich durch die Verwendung von Komma und Punkt. Allerdings kann auch ein lokaler Computer anders eingestellt worden sein.
3,142 3,141592653589793 1.000.000.000,01 3.142 3.141592653589793 1,000,000,000.01
Offenbar ist der Sprachraum auch wichtig für Zahleingaben. Dazu fügen wir folgende Zeilen hinzu
try { double x = numberformat.parse(numberformat.format(1000000000.01)) .doubleValue(); System.out.println(x); } catch (ParseException e) { }
Die Ausgabe zeigt, dass ein Formatierer seine eigenen Ausgabe lesen kann (auch wenn sie z.B. Gruppierungen enthält). Zurückgegeben wird ein Objekt Number, dessen Methoden man zur Umformatierung in Zahlen verwenden kann.
Die Alternative
System.out.println(Double.valueOf("100.23").doubleValue());
funktioniert nur mit Zahlen, die im Englischen Format mit Dezimalpunkt formatiert sind. Die Wrapper-Klasse Double für den eingebauten Datentyp double macht aus dem eingebauten Typ ein Objekt. Sie ist dazu gedacht, double-Werte in Datenstrukturen zu speichern, die nur Objekte akzeptieren, wie zum Beispiel Hashtables. Double hat die gezeigte statistische Methode zur Umwandlung von String nach Double.
Es existieren auch Formatierer für Währungseinheiten, Prozentwerte und Daten. Wir demonstrieren alle drei in einem Programm.
import java.text.DateFormat; import java.text.NumberFormat; import java.util.Date; public class Test { public static void main (String args[]) { NumberFormat price = NumberFormat.getCurrencyInstance(); NumberFormat percent = NumberFormat.getPercentInstance(); System.out.println(price.format(12.31)); percent.setMinimumFractionDigits(2); System.out.println(percent.format(0.1231)); DateFormat date = DateFormat.getDateInstance(DateFormat.SHORT); System.out.println(date.format(new Date())); date = DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.LONG); System.out.println(date.format(new Date())); } }
Die Ausgabe ist
12,31 DM 12,31% 29.06.98 29. Juni 1998 11:46:10 GMT+02:00
Die Klasse Date behandelt ein Datum. Sie ist insbesondere von der aktuellen Zeitzone betroffen.
Ein weiteres Gebiet für Internationalisierung ist die Ausgabe von Programmen in internationaler Form. Als Beispiel zeigen wir hier ein japanisches Java-Programm.
Wie man sieht, sind alle Menütexte japanisch. Das gleiche sollte für Fehlermeldungen und Hilfetexte gelten.
Um ein solches Programm zu erzeugen, sollte man die verwendeten Strings aus einer Ressource auslesen. Dazu verwendet man Property-Dateien, deren Namen aus einem String mit angehängtem Sprachraum und der Dateierweiterung .properties besteht. Ein Beispiel ist Test_de.properties. Java wählt diese Ressourcen-Datei automatisch aus, wenn man sich im deutschen Sprachraum befindet (oder Local.setDefault entsprechend eingestellt hat) und Ressourcen-Bündel verwendet. Dies geschieht am zweckmäßigsten in einer statischen Variable der Hauptklasse.
Als Beispiel erstellt man in dem Verzeichnis, wo sich die Klasse verwendet zwei Property-Dateien Test.properties und Test_de.properties mit einer Property Test, die einmal den Wert English und einmal den Wert Deutsch hat. Auf einem deutschen System wird die zweite verwendet. In jedem anderen Land die erste.
import java.util.ResourceBundle; public class Test { static ResourceBundle B; // verwendetes Bundle public static void initBundle () // Initialisiere B { try { B = ResourceBundle.getBundle("Test"); } catch (Exception e) { B = null; } } public static void main (String args[]) // Zirkel wird als Applikation aufgerufen { initBundle(); if (B != null) System.out.println(B.getString("Test")); } }