Javaschubla.de - Java als erste Programmiersprache

Arrays

Manchmal will man viele Variablen desselben Typs haben. Es wäre sehr hinderlich, die alle einzeln deklarieren zu müssen und jedes Mal einzeln behandeln zu müssen. Stattdessen definiert man ein Array (deutsch: Feld).

    Typ[] arrayName = new Typ[größe];

Z.B.

    int[] zahlen = new int[10];

Einen Arraytyp erhält man also einfach, indem man hinter den Typ der einzelnen Elemente (hier int) eckige Klammern setzt:

    int[] zahlen;

Arrays sind in Java Objekte. Also muss man ein neues Array mit new erzeugen. Dann kommt wieder der Typ - hier gibt man in den eckigen Klammern die Größe des Arrays an.

    zahlen = new int[10];

Arrays sind von 0 bis Größe-1 durchnummeriert. Auf die einzelnen Array-Elemente greift man mit eckigen Klammern und dem Index zu:

    zahl[0] = 5;
    zahl[1] = -32000;
    ...
    zahl[9] = 888;

Achtung, nicht aus Versehen auf zahl[10] zugreifen, die gibt es nicht. Man würde eine ArrayIndexOutOfBoundsException erhalten.

Wenn wir jetzt mit allen zehn Zahlen dasselbe machen wollen, beispielsweise jede um 15 erhöhen, können wir das einfach in einer Schleife machen:

    for (int i = 0; i < zahlen.length; i++)
    {
      zahlen[i] += 15;
    }

Wenn wir statt des Arrays 10 Variablen gehabt hätten, hätten wir jetzt 10 Anweisungen hinschreiben müssen: zahl0 +=15; zahl1 +=15; ... zahl9 +=15;

mit arrayName.length erhält man die Länge des Arrays. Beachte, dass im Gegensatz zu Strings hier keine runden Klammern kommen - length ist ein Attribut des Arrays, keine Methode wie bei String. Das Attribut length ist allerdings unveränderlich.

Übung (Arrays, Methoden, Schleifen, von der Tastatur einlesen, Division)

Schreibe ein Programm mit einer main-Methode und einer weiteren Methode mit dem Namen durchschnitt. In der main-Methode soll der Benutzer 10 Zahlen eingeben. Die durchschnitt()-Methode erwartet ein int-Array und gibt den Durchschnitt als double zurück.

Erweiterung: Schreibe eine Testmethode (wenn du willst, in einer anderen Klasse) für die durchschnitt()-Methode. Überleg dir verschiedene Arrays, die du testen willst (z.B. positive und negative Zahlen, Arrays mit nur einem Element). Bei doubles ist es sinnvoller, auf eine maximale Toleranz (z.B. 0.0001) zu testen statt mit ==, denn kleine Rundungsabweichungen gibt es fast immer. Mindestens sollte jeweils passed oder failed ausgegeben werden. Überleg dir weitere sinnvolle Ausgaben.

Kommandozeilenparameter

public static void main(String[] args) - die main-Methode erwartet als Parameter ein String-Array. Dieses bekommt sie von der JVM auch übergeben, es enthält die Kommandozeilenparameter.

Beispiel:

class Kommando
{
  public static void main(String[] args)
  {
    System.out.println(args[0]);
  }
}

Normal mit javac kompilieren. Aber mit

java Kommando test

aufrufen. Es wird test ausgeben.

Aber wenn man es ohne Kommandozeilenparameter aufruft, erhält man eine ArrayIndexOutOfBoundsException. Denn dann hat args die Länge 0, man kann also nicht auf das erste Element (mit der Nummer 0) zugreifen, weil es das gar nicht gibt.

Alle Kommandozeilenparameter ausgeben:

class Kommando
{
  public static void main(String[] args)
  {
    for (int i = 0; i<args.length; i++)
    { 
      System.out.println(args[i]);
    }
  }
}

Wenn man keine Kommandozeilenparameter übergibt, passiert nichts. Dann ist args.length gleich 0, also wird die Schleife nie ausgeführt, weil 0 < 0 schon zu Anfang nicht erfüllt ist.

for-in-Schleife (auch: for-each-Schleife)

Wenn man alle Elemente eines Arrays (oder einer Collection) durchgehen will, kann man dafür die for-in-Schleife benutzen:

class Kommando
{
  public static void main(String[] args)
  {
    for (String argument : args)
    { 
      System.out.println(argument);
    }
  }
}

Lies: "Für jeden String argument in args { ... }"

Übungen (Kommandozeilenparameter, Arrays, Schleifen, Integer.parseInt, if)

  1. Schreibe ein Programm, das die Kommandozeilenparameter in umgekehrter Reihenfolge ausgibt.
  2. Schreibe ein Programm namens Summe, das zwei Kommandozeilenparameter erwartet und die Summe ausgibt. Wenn nur einer oder gar keiner übergeben wird, soll es darauf hinweisen, dass es zwei benötigt und dann abbrechen.

Das folgende Programm gibt die Kommandozeilenparameter in normaler Reihenfolge aus, aber die Buchstaben jedes Wortes werden verdreht. Dafür sind zwei ineinandergeschachtelte Schleifen notwendig. Ich empfehle, bei geschachtelten Schleifen nirgends i als Zählvariable zu verwenden, wie man es sonst üblicherweise tut, weil man es sonst ganz leicht an der falschen Stelle verwendet, wo man eigentlich einen anderen Zählindex meinte.

Mit return kann eine Methode vorzeitig beendet werden. Da es sich hier um die main-Methode handelt, wird dadurch an der Stelle das Programm beendet.

class KommandoSpiegel
{
  public static void main(String[] args)
  {
    if (args.length == 0)
    {
      System.out.println("Mindestens einen Parameter übergeben!");
      return;
    }

    for (int a = 0; a<args.length; a++)
    {
      String kommando = args[a];
      for (int b = kommando.length()-1; b >= 0; b--)
      {
        System.out.print(kommando.charAt(b));
      }
      System.out.print(" ");
    }
  }
}

Die äußere Schleife kann durch eine for-in-Schleife ersetzt werden.

class KommandoSpiegel2
{
  public static void main(String[] args)
  {
    if (args.length == 0)
    {
      System.out.println("Mindestens einen Parameter übergeben!");
      return;
    }

    for (String kommando : args)
    {
      for (int b = kommando.length()-1; b >= 0; b--)
      {
        System.out.print(kommando.charAt(b));
      }
      System.out.print(" ");
    }
  }
}

Übung

Schreibe das Programm so um, dass es eine separate Methode gibt, die ein String-Array erwartet und ein String-Array zurück gibt mit den verdrehten Wörtern.

Schreibe eine Testmethode für diese Methode (evtl. in einer separaten Klasse). Beim Ergebnis ist es sinnvoll erst einmal zu testen, ob beide Arrays die gleiche Länge haben. Denk daran, den Inhalt nicht mit ==, sondern mit equals zu vergleichen. Welche Ausgabe neben passed und failed könnte sinnvoll sein?

Mehrdimensionale Arrays

Ein 2x3-Integer-Array definiert man so:

    int[][] array = new int[2][3];

Ob man sich die beiden Dimensionen dabei als x- und y-Koordinaten oder umgekehrt als Zeilen- und Spaltennummer vorstellt, bleibt einem selbst überlassen.

Man kann auch nicht-rechteckige Arrays definieren. Ein zweidimensionales Array ist ja nichts weiter als ein Array, dessen Elemente wiederum Arrays sind. Im obigen Beispiel ist das 2x3-Array eigentlich ein Array mit zwei Elementen, und diese beiden Elemente sind zufällig gerade int-Arrays mit jeweils drei Elemente. Das hätte man auch so definieren können:

    int[][] array = new int[2][];
    array[0] = new int[3];
    array[1] = new int[3];

Genau so funktioniert es mit den nicht-rechteckigen Arrays:

    int[][] array = new int[2][];
    array[0] = new int[3];
    array[1] = new int[4];

Implizite Arrays

    int[] array = {100, -15, 8};

ist eine Kurzschreibweise für

    int[] array = new int[3];
    array[0] = 100;
    array[1] = -15;
    array[2] = 8;

Eine andere gleichbedeutende Notation ist:

    int[] array = new int[]{100, -15, 8};

Dynamische Arrays?

Arrays in Java können ihre Größe nicht ändern. Dafür gibt es Collections (Sammlungen), insbesondere Listen (java.util.ArrayList, java.util.LinkedList). (Hinweis: java.util.Vector ist veraltet.)


In der nächsten Lektion geht es noch einmal Strings. Es wird noch eine dritte String-Lektion folgen.