Varargs in Java
- Vereinfachte Synopsis
java.util.Arrays.asList( java.lang.Object ... a )
java.util.List< E >.of( E ... elements )
Die Schreibweise mit den drei Punkten bei einer Parameterdeklaration steht für eine beliebige Anzahl von Argumenten des vor den drei Punkten angegebenen Typs.
Die of-Methode ergibt eine nicht-modifizierbare Liste mit Wertsemantik, die keine Nullreferenz enthalten darf.
List in Java
Ein ArrayList-Objekt ähnelt einer Reihung oder einer HBox. Es kann aber keine elementaren Werte direkt enthalten, sondern nur Referenzwerte. Reihungen mit elementaren Werten sind eventuell schneller und speichersparender. Dafür sind ArrayList-Objekte flexibler, sie können beispielsweise zur Laufzeit erweitert werden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( java.util.List.of( 4, 9 )); }}- transcript
[4, 9]
In dem obigen Beispiel werden int-Werte stillschweigend in java.lang.Integer-Objekte verpackt.
»asList« ist eine varargs-Methode (dieser Begriff ist hier neu). Zudem wird bei den Argumenten auch noch Autoboxing verwendet.
Das folgende Beispiel zeigt, daß eine Liste als heterogener Behälter verwendet werden kann, die Zahlen, Texte und sogar eine Referenz auf sich selbst speichern kann.
Dies liegt daran, daß die Liste eigentlich Referenzen auf Objekte vom Typ »java.lang.Object« enthält, alle elementaren Werte, werden daher zunächst in entsprechende Hüllobjekte verpackt und dann als Untertypen von »java.lang.Object« in der Liste akzeptiert.
Die Verwendung des Obertyps »List« als Typ der Variablen »list« ist typisch und deutet an, daß auch eine andere Implementation der Schnittstelle »List« verwendet werden kann.
Main.java
public final class Main
{ @java.lang.SuppressWarnings( { "rawtypes", "unchecked" })
public static void main( final java.lang.String[] args )
{ final java.util.List list = new java.util.ArrayList();
java.lang.System.out.println( list );
list.add( 2 ); java.lang.System.out.println( list );
list.add( 2.3 ); java.lang.System.out.println( list );
list.add( "alpha" ); java.lang.System.out.println( list );
list.add( list ); java.lang.System.out.println( list ); }}transcript
[]
[2]
[2, 2.3]
[2, 2.3, alpha]
[2, 2.3, alpha, (this Collection)]
Dasselbe mit einem anderen Listentyp:
Main.java
public final class Main
{ @java.lang.SuppressWarnings( { "rawtypes", "unchecked" })
public static void main( final java.lang.String[] args )
{ final java.util.List list = new java.util.LinkedList();
java.lang.System.out.println( list );
list.add( 2 ); java.lang.System.out.println( list );
list.add( 2.3 ); java.lang.System.out.println( list );
list.add( "alpha" ); java.lang.System.out.println( list );
list.add( list ); java.lang.System.out.println( list );
java.lang.System.out.println( list );
}}transcript
[]
[2]
[2, 2.3]
[2, 2.3, alpha]
[2, 2.3, alpha, (this Collection)]
[2, 2.3, alpha, (this Collection)]
Semantik der Untertypbeziehung
Die verschiedenen Implementationen einer Schnittstelle sind insofern untereinander austauschbar als daß sie alle die Dokumentation der Schnittstelle erfüllen. Sie können sich noch in folgender Hinsicht unterscheiden:
- Unterschiede sind möglich bei den Dingen, zu denen in der Dokumentation der Schnittstelle nichts gesagt wurde. Dies können beispielsweise nichtfunktionale Eigenschaften sein, wie etwa die Zeit, welche bestimmte Operationen benötigen.
- Genauso kann ein Untertyp auch noch Operationen zu einem Objekt hinzufügen, welche es in der Schnittstelle nicht gibt.
Falls man ein Objekt eines speziellen Untertyps benötigt, so wird man dann auch der Variablen diesen Typ geben.
Wann Reihungen?
Klassische Reihungen können noch von Vorteil sein, wenn eine Vielzahl von Werten elementarer Typen (wie »int« oder »double«) gespeichert werden soll, da dann der Aufwand für das Verpacken und Entpacken solcher Wert in Objekte entfällt, weil diese in einer Reihung des passenden Typs (wie »int[]« oder »double[]«) direkt gespeichert werden können.
Bei Listen von Referenzen kann es auch zu einer Verlangsamung des Programmes kommen, weil die referenzierten Objekte nicht nahe beieinander im Speicher angelegt werden, hier sind Reihungen elementarer Werte effizienter.
Teilnehmerfrage „Wie kann ich eine Liste sortieren und dann effizient darin suchen?“ (gestellt 2018-07-06T11:40+02:00)
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final var list = java.util.Arrays.asList
( "alpha", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota",
"kappa", "lambda", "mu", "nu", "xi", "omicron", "pi", "rho", "sigma",
"tau", "upsilon", "phi", "chi", "psi", "omega" );java.lang.System.out.println( list );
java.util.Collections.sort( list );
java.lang.System.out.println( list );
for( int i = 0; i < list.size(); ++i )
java.lang.System.out.printf( "%2d \"%s\"\n", i, list.get( i ));java.lang.System.out.println
( java.util.Collections.binarySearch( list, "omicron" )); }}- transcript
[alpha, gamma, delta, epsilon, zeta, eta, theta, iota, kappa, lambda, mu, nu, xi, omicron, pi, rho, sigma, tau, upsilon, phi, chi, psi, omega]
[alpha, chi, delta, epsilon, eta, gamma, iota, kappa, lambda, mu, nu, omega, omicron, phi, pi, psi, rho, sigma, tau, theta, upsilon, xi, zeta]
0 "alpha"1 "chi"
2 "delta"
3 "epsilon"
4 "eta"
5 "gamma"
6 "iota"
7 "kappa"
8 "lambda"
9 "mu"
10 "nu"
11 "omega"
12 "omicron"
13 "phi"
14 "pi"
15 "psi"
16 "rho"
17 "sigma"
18 "tau"
19 "theta"
20 "upsilon"
21 "xi"
22 "zeta"
12
Laufzeiteffizienz von Listen
Da Listen nur Referenzen auf Objekte enthalten, und die Objekte sich dann verstreut irgendwo im Speicher befinden können, sind Zugriffe auf die einzelnen Werte einer Liste beim Durchlaufen der Liste wesentlich langsamer als bei Reihungen elementarer Werte (wie »int[]«), bei denen alle Werte gleich in der Reihung enthalten sind. Dafür sind Listen flexibler und einfacher zu verwenden, so daß sie für Zahl bevorzugt verwendet werden sollten, wenn Laufzeiteffizienz keine so große Rolle spielt.
Übungsaufgabe
In den obigen Programmbeispielen werden Zeilen wie »list.add( list ); java.lang.System.out.println( list );« oft wiederholt. Schreiben Sie eine Methodendeklaration, um solche Zeilen zu zentralisieren!