Variable Anzahl von Argumenten in Java
Die Formatierung mit »java.lang.String.format« erlaubt es, Zahlen übersichtlich darzustellen und verschiedene Arten von Zeichenfolgen mit relativ wenig Programmieraufwand zu erzeugen.
Zeilenenden
Im folgenden sieht man einmal die Ausgabe der Zeichenfolge »"a%nb"« und einmal die Ausgabe der Zeichenfolge »java.lang.String.format( "a%nb" )«.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "a%nb" ); }}Protokoll
a%nb
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "a%nb" )); }}Protokoll
a
b
In »java.lang.String.format( "a%nb" )« sind alle Vorkommen von »%n« durch ein Zeilenende ersetzt worden.
Das folgende Programm zeigt die Erzeugung einer Zeichenfolge mit den Werten mehrerer Ausdrücke auf mehreren Zeilen.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( ( 2 + 3/2 )+ "%n" +( 2 + 3/2. ) )); }}Protokoll
3
3.5
Die Zeichenfolge, welche zur Zeilentrennung dient, ist auch als Wert des Aufrufs »java.lang.System.lineSeparator()« verfügbar, so daß auch das folgende Programm zwei Zeilen ausgibt.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( ( 2 + 3/2 )+ java.lang.System.lineSeparator() +( 2 + 3/2. )); }}Protokoll
3
3.5
Aufruf als Operand
Der Aufruf von »java.lang.String.format« mit dem Typ »java.lang.String« kann seinerseits auch wieder ein Operand sein,
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "x" + java.lang.String.format( "a%nb" )+ 2 ); }}Protokoll
xa
b2
Vararg-Parameter
»format« kann auch mit zwei oder drei Ausdrücken in den Klammern verwendet werden. Allerdings wird in dem folgenden Programm nur der erste Ausdruck zurückgegeben.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "alpha", "gamma", "delta" )); }}Protokoll
alpha
Tatsächlich können in den Klammern hinter »format« auf den ersten Ausdruck beliebig viele weitere mit einem Komma abgetrennte Ausdrücke folgen. Man sagt auch, daß »format« ein variable Stelligkeit (variable Arität ) habe oder variadisch sein.
Im Falle dieser Methode dürfen die verwendeten Ausdrücke nach dem ersten Argument auch jeden der drei Typen »int«, »double«, oder »java.lang.String« haben.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "alpha", 1, 1.2, java.lang.Math.random() )); }}Protokoll
alpha
Proklamation variabler Stelligkeit (variabler Arität)
In der folgenden vereinfachten Proklamation wird variable Stelligkeit (variable Arität) der Methode »format« durch eine Elipse »...« ausgedrückt.
- Proklamation zu »java.lang.String.format« (vereinfacht)
format( java.lang.String text, ... args )
Wir sagen, daß jene Methode zwei Parameter habe (»text« und »args«), aber ein Aufruf jener Methode beliebig viele Argumente haben kann (außer null Argumenten). Der zweite Parameter mit der Ellipse drückt aber aus, daß ab jener Stelle beliebig viele Argumente verwendet werden dürfen.
Texteinsetzungen
Die Argumente hinter dem ersten Argument, nennen wir auch Zusatzargumente. Im Aufruf »java.lang.String.format( "alpha%s", "gamma" )« ist beispielsweise »"alpha%s"« das erste Argument und »"gamma"« das erste Zusatzargument.
Für das »%s« im Text des ersten Ausdrucks in den Klammern wird der Text des ersten Zusatzarguments in den Klammern eingesetzt.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "alpha%s", "gamma" )); }} /*
^ |
'-------' */Protokoll
alphagamma
Allgemein wird (etwas vereinfacht) für jeden Platzhalter der Form »%s« ein hinsichtlich seiner Position entsprechender weiterer Ausdruck eingesetzt. Für den ersten Platzhalter wird das erste Zusatzargument eingesetzt, für den zweiten Platzhalter das zweite Zusatzargument und so weiter.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "alpha%s%s", "gamma", "delta" )); }} /*
^ ^ | |
| '-------|--------'
'---------' */Protokoll
alphagammadelta
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "[%s]=(%s)", "alpha", "gamma" )); }} /*
^ ^ | |
| '--------|--------'
'-------------' */Protokoll
[alpha]=(gamma)
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%s%n%s", "alpha", "gamma" )); }} /*
^ ^ | |
| '-------|---------'
'-----------' */Protokoll
alpha
gamma
Format und Formatspezifizierer
Der erste Ausdruck in den Klammern hinter von »java.lang.System.out.format« wird auch Format genannt, die mit einem Prozentzeichen beginnenden und mit einem Buchstaben endenden Angaben (wie »%s«) Formatspezifizierer.
Das Format ähnelt einem Formular mit Platzhaltern (Textfeldern), in die dann Werte eingesetzt werden können.
Verketten von Zeichenfolgen (Refaktor)
Wir kennen damit nun zwei Möglichkeiten zum Herstellen einer Verkettung von Zeichenfolgen.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%s%s", "alpha", "gamma" )); }} /*
^ ^ | |
| '-------|--------'
'---------' */Protokoll
alphagamma
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "alpha" + "gamma" ); }}Protokoll
alphagamma
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "Die Temperatur betraegt %s Grad Celsius.", 22 )); }}Protokoll
Die Temperatur betraegt 22 Grad Celsius.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "Die Temperatur betraegt " + 22 + " Grad Celsius." ); }}Protokoll
Die Temperatur betraegt 22 Grad Celsius.
In dem folgenden Programm muß die Summe eingeklammert werden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "7 + 8 = " +( 7 + 8 )+ "." ); }}Protokoll
7 + 8 = 15.
Wenn aus dem Summanden ein Argument wird, sind keine Klammern mehr nötig. Außerdem entfällt in dem folgenden Programm die recht aufwendige Schreibweise »+ "."« zum Anfügen eines Punktes. Andererseits mußte ein Methodenaufruf eingefügt werden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "7 + 8 = %s.", 7 + 8 )); }}Protokoll
7 + 8 = 15.
Nachkommastellen
Zur Darstellung von double-Werten in einer Schreibweise ohne »E« kann »%f« verwendet werden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%s%n%f", 0.000001, 0.000001 )); }}Protokoll
1.0E-6
0,000001Protokoll
1.0E-6
0.000001
Bei der Verwendung des Formatspezifizierers »%f« muß das entsprechende Zusatzargument von einem Gleitkommatyp (wie »double«) sein, ein ganzzahliger Typ (wie »int«) ist hier nicht erlaubt.
Es ist möglich, daß auf einem Computer mit entsprechenden Umgebungseinstellungen bei Formatierung mit »%f« ein Komma als Dezimaltrennzeichen verwendet wird. (Dabei werden oft nicht die Einstellungen der Umgebung für das Dezimaltrennzeichen, sondern die für das Land beachtet.)
Nach einem Prozentzeichen kann auch noch ein ganzzahliges Numerale nach einem Punkt eingefügt werden, welches die Genauigkeit (hier: die Anzahl der Nachkommastellen) der Formatierung eines Zahl angibt.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%.2f", 12.0 )); }}Protokoll
12,00
Protokoll
12.00
Mit »%.0f« können alle Nachkommastellen versteckt werden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%.0f", 12.0 )); }}Protokoll
12
»%f« steht für »%.6f«.
Der Wert wird zum Erreichen der gewünschten Stellenzahl gerundet.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%.2f; %.2f; %.2f", 0.854, 0.855, 0.856 )); }}Protokoll
0,85; 0,86; 0,86
Protokoll
0.85; 0.86; 0.86
Das folgende Programm rechnet falsch und gibt dann auch noch unverhältnismäßig viele Nachkommastellen aus.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( 120 * 1.11 ); }}Protokoll
133.20000000000002
Durch die Beschränkung der Anzahl der Nachkommastellen wird der Wert so gerundet, daß der Rechenfehler versteckt wird.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%.2f", 120 * 1.11 )); }}Protokoll
133,20
Protokoll
133.20
Kennzahlen von Schriftzeichen
Der Formatspezifizierer »%c« verlangt die Darstellung einer int-Zahl durch das Schriftzeichen, welches diese Zahl als Kennzahl hat. Das Zeichen mit der Kennzahl 65 ist das »A«.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%c%c%c", 64, 65, 66 )); }}Protokoll
@AB
- ASCII -Code-Tabelle
32 48 0 64 @ 80 P 96 ` 112 p
33 ! 49 1 65 A 81 Q 97 a 113 q
34 " 50 2 66 B 82 R 98 b 114 r
35 # 51 3 67 C 83 S 99 c 115 s
36 $ 52 4 68 D 84 T 100 d 116 t
37 % 53 5 69 E 85 U 101 e 117 u
38 & 54 6 70 F 86 V 102 f 118 v
39 ' 55 7 71 G 87 W 103 g 119 w
40 ( 56 8 72 H 88 X 104 h 120 x
41 ) 57 9 73 I 89 Y 105 i 121 y
42 * 58 : 74 J 90 Z 106 j 122 z
43 + 59 ; 75 K 91 [ 107 k 123 {
44 , 60 < 76 L 92 \ 108 l 124 |
45 - 61 = 77 M 93 ] 109 m 125 }
46 . 62 > 78 N 94 ^ 110 n 126 ~
47 / 63 ? 79 O 95 _ 111 o
Auswahl von Zusatzargumenten an Hand ihrer Position
Folgt direkt auf das Prozentzeichen eine ganzzahliges Numerale und ein Dollarzeichen »$« kann man damit aber auch einen Ausdruck an Hand seiner Position auswählen. In dem folgenden Programmbeispiel findet man beispielsweise »1$« und »2$«.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%2$s%1$s%1$s", "---", "ooo" )); }}Protokoll
ooo------
Diese Technik der ausdrücklichen Angabe der Kennzahl eines bestimmten Ausdruck kann auch mit den anderen vorgestellten Möglichkeiten kombiniert werden. So wird beispielsweise aus »1$« und »%.2f« »%1$.2f«.
Das folgende Programmbeispiel zeigt, wie dieselbe Zufallszahl zweimal ausgegeben werden kann – etwas, das sonst ohne Gebrauch von Variablen nicht möglich ist.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%1$s%n%1$s%n", java.lang.Math.random() )); }}Protokoll
0,42111863729075484
0,42111863729075484Protokoll
0.42111863729075484
0.42111863729075484
Darstellungen in verschiedenen Zahlensystemen
Eine nicht-negative ganze Zahl kann mit »%d«, »%x« und »%o« im Dezimalsystem, im Hexadezimalsystem (dem Stellenwertsystem zur Basis 16) beziehungsweise im Oktalsystem (dem Stellenwertsystem zur Basis 8) ausgegeben werden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%d", 35 )); }}Protokoll
35
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%x", 35 )); }}Protokoll
23
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%o", 35 )); }}Protokoll
43
Die Schreibweise »35« im normalen Zehnersystem zur Basis 10 bedeutet ja ‹ 3 × 10 + 5 ›, »23« im Hexadezimalsystem zur Basis 16 bedeutet entsprechend ‹ 2 × 16 + 3 ›, die Schreibweise »43« im Oktalsystem zur Basis 8 bedeutet ‹ 4 × 8 + 3 ›.
Auch bei diesen Arten der Formatierung ist die Angabe einer Zusatzargumentposition möglich.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%1$d", 35 )); }}Protokoll
35
Die Formatierungen ins Hexadezimalsystem und ins Oktalsystem werden nur relativ selten benötigt.
Bei Verwendung von »%d«, »%x« oder »%o« muß das entsprechende Zusatzargument von einem ganzzahligen Typ (wie »int«) sein, ein Gleitkommatyp (wie »double«) ist hier nicht erlaubt.
Darstellung des Prozentzeichens »%«
Ein Prozentzeichen kann mit dem Formatspezifizierer »%s« dargestellt werden, indem das Prozentzeichen als Zusatzargument verwendet wird.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%sn%nabc", "%" )); }}Protokoll
%n
abc
Das Prozentzeichen kann auch außerhalb des format-Aufrufs angegeben werden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "%" + java.lang.String.format( "n%nabc" )); }}Protokoll
%n
abc
Ein Prozentzeichen kann auch mit dem speziellen Formatspezifizierer »%%« dargestellt werden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%%n%nabc" )); }}Protokoll
%n
abc
Tausendertrennzeichen
Die Option »,« kann für die Umwandlungen »d« und »f« verwendet werden, um eine Ausgabe mit Tausendertrennzeichen zu erreichen. Eine Option wird direkt vor die Angabe der Genauigkeit geschrieben (die auch fehlen kann).
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "%,f", 987654321.123456789 )); }}Protokoll
987.654.321,123457
Protokoll
987,654,321.123457
Unbedingte Auswertung
Alle Stellen von Methodenaufrufen sind strikt, das heißt, daß Argumente bei der Auswertung eines Aufrufs einer Methode alle ausgewertet werden (selbst, wenn ihr Wert gar nicht benötigt werden sollte.)
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "0.0", java.lang.Math.random() )); }}
Obwohl beim Format »0.0« das Ergebnis immer »0.0« ist, wird »java.lang.Math.random()« trotzdem ausgewertet!
Einsetzen eines Ausdrucks in den Ausdruckrahmen *
Das folgende Programmbeispiel zeigt das Einsetzen eines Ausdrucks in den Ausdruckrahmen.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format
("public final class Main%n" +
"{ public static void main( final java.lang.String[] args )%n" +
" { java.lang.System.out.println%n" +
" ( %s ); }}",
"java.lang.Math.random()" )); }}Protokoll
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.Math.random() ); }}
Beispiel Angabe einer Umgebung
Eine gewünschte Umgebung kann bei einer Überladung von »java.lang.String.format« auch explizit als erstes Argument angegeben werden. Hierzu wird eine bestimmte Konstante mit einem symbolischen Namen für den sogenannten „Schauplatz “ übergeben.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( java.util.Locale.GERMANY, "%f", 0.000001 )); }}Protokoll
0,000001
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( java.util.Locale.US, "%f", 0.000001 )); }}Protokoll
0.000001
- Aussprachehinweis
- locale lo ˈkæl
Mit dem Aufruf »java.util.Locale.setDefault( java.util.Locale.US )« kann der Schauplatz dauerhaft auf »java.util.Locale.US« umgestellt werden.
Zusammenfassung
Die Methode »java.lang.String.format« ist vor allem nützlich, um
- mehrere Werte zu einem Text zusammenzufassen und
- Zahlen in einem bestimmten Zahlenformat, etwa mit einer bestimmten Anzahl von Nachkommastellen, darzustellen.
Übungsfragen
? Übungsfrage
Welche Ausgabe erzeugt das folgende Programm?
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format( "a" )+ java.lang.String.format( "b" )); }}
? Übungsfrage *
Welche Ausgabe erzeugt das folgende Programm?
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.String.format
( "Sie haben %" +
java.lang.String.format( "%.0f", java.lang.Math.random() * 2 )+
"$s!",
"gewonnen",
"verloren" )); }}