Sitzung: Jeden Freitag in der Vorlesungszeit ab 16 Uhr c. t. im MAR 0.005. In der vorlesungsfreien Zeit unregelmäßig (Jemensch da?). Macht mit!

Javakurs2006/Java Kurzreferenz

Hier befindet sich eine kleine Referenz für Java speziell für den Javakurs der Freitagsrunde.

Kommentare

Ein Kommentar ist ein Abschnitt des Java-Codes, der vom Java-Compiler ignoriert wird. Man kann in ein Kommentar also schreiben was man will. Kommentare sind nützlich, um den Quellcode zu dokumentieren.

In Java gibt es zwei Arten von Kommentaren:

Kommentare über eine Zeile

// Diese ganze Zeile wird vom Compiler ignoriert.
int x= 5;  // Dieser  Kommentar beginnt mit »//«.  Alles davor wird vom Compiler nicht ignoriert.

Kommentare über mehrere Zeilen

/* Dieser 
   Kommentar
   erstreckt 
   sich 
   über
   mehrere
   Zeilen.
*/

Zum Vergleich: in Opal werden Kommentare mit -- eingeführt.

Javadoc-Kommentare

Um Programme zu dokumentieren gibt es in Java ein Tool: Javadoc. Damit lassen sich HTML-Seiten generieren, die informationen über eure Methoden und Klassen beinhalten.

/**
 Dies ist ein Javadoc-Kommentar 
 und erscheint später in eurer Dokumentation.
 Was es für Optionen gibt, fragt eure Tutoren ;)
*/

Datentypen (Variablen)

Typ Speicherbedarf Bereich
void 0 Byte keiner
boolean 1 Byte true, false
int 4 Byte -2.147.483.648 bis 2.147.483.647
short 2 Byte -32.768 bis 32.787
long 8 Byte -9.223.372.036.854.775.808L bis 9.223.372.036.854.775.807L
byte 1 Byte -128 bis 127
float 4 Byte +/-3,40282347E+38F
double 8 Byte +/-1,79769313486231570E+308

Boolsche Operatoren

Operator Beispiel Ergebnis des Beispiels
==

(gleich)

4 == 9 false
!=

(ungleich)

4 != 8 true
&&

(logisches UND)

false && true false, es wird erst der linke Ausdruck ausgewertet. Wenn die Auswertung false ergibt, wird der rechte Ausdruck nicht mehr geprüft, da das Ergebnis nicht mehr true werden kann.
||

(logisches ODER)

true || false true, es wird erst der linke Ausdruck ausgewertet. Wenn die Auswertung true ergibt, wird der rechte Ausdruck nicht mehr geprüft, da das Ergebnis nicht mehr false werden kann.
<, <=, >, >=, <> 1 < 3 (hier exempalrisch nur eins) true

Bitoperatoren

Operator Beschreibung Erklärung
& AND Wie das logische UND, jedoch werden auf jeden Fall beide Seiten ausgewertet.
| OR Wie das logische ODER, jedoch werden auf jeden Fall beide Seiten ausgewertet.
^ XOR Exklusives ODER
~ NOT Negation des Wertes.

Konstanten

  • In Java werden Konstanten mit dem Schlüsselwort final bezeichnet. In Java gibt es die Konvention Konstanten komplett groß zu schreiben:
final double PI = 3.14;

Zuweisungen und Initialisierungen

Wenn man eine Variable erstellt und sie mit Werten füllen will, wird man auf folgende Syntax stoßen:

Datentyp Variablenname = Initialisierungswert;

Es gibt zwei Möglichkeiten diese Aktion durchzuführen:

  • lange Variante:
int zahl;
zahl = 23;
  • kurze Variante:
int zahl = 23;

if-Anweisung

  • Die einfachste Variante:
if (condition) {
   Anweisungen;	
}
  • Zusätzlich hat diese Variante einen alternativen Anweisungsblock. Wenn condition nicht erfüllt gehe in den else-Zweig und führe dort die Anweisungen aus.
if (condition) {
   Anweisungen;	
} else {
   Anweisungen;
}
  • Natürlich lassen sich beide Varianten schachteln. Man kann also auf zwei Bedingungen prüfen und bei nicht Eintreffen in den else-Zweig gehen.
if (condition) {
   Anweisungen;	
} else if (condition) {
   Anweisungen;			
} else {
   Anweisungen;		
}

Schleifen

for-Schleife

  • Um über Array's zu wandern bietet sich die for-Schleife an. Als erstes in der Klammer muß eine Laufvariable deklariert und mit einem Wert initialisiert werden (hier int i= 0). Danach muß eine Bedingung erfüllen, um festzulegen bis wann die Schleife ausgeführt wird (i < 10). Als letztes muß die Laufvariable verändert werden, so daß irgendwann der Abbruch eintritt (i++).
for (int i = 0; i < 10; i++) {

   Anweisungen;

}

while-Schleife

  • Die while-Schleife wird meistens dafür benutzt, Anweisungen auszuführen bis irgendetwas eintrifft (z.B. EOF -End Of File). Für Arrays sollte man die for-Schleife nehmen. Die while-Schleife lässt sich auch als for-Schleife schreiben.
while (condition) {
    Anweisungen;
}

switch-case

  • Wenn man verschiedene Werte abfangen möchte, wie zum Beispiel verschiedene Zahlen (bei einem Menü). Gehen wir mal davon aus, daß wir drei Menüeinträge haben:
  1. 1
  2. 2
  3. 0

1 gibt die Zahl 1, 2 gibt die Zahl 2 aus und 0 beendet das Programm, dann ist key zum Beispiel ein int und value würde den einzelnen Menüpunkten entsprechen. Das break bewirkt ein rausspringen aus dem switch-Konstrukt. Würde man das break weglassen, würden sämtliche Anweisungen die direkt darunter folgen, ausgeführt werden.

switch (key) {
   case value: {
      Anweisungen;
      break;
   }
   default: {
      Anweisungen;
      break;
   }
}

Leider ist switch/case in Java nicht wirklich konsequent umgesetzt, sodass sich wirklich nur Werte ganzahligen Typs (Byte, Short und Integer) mit dieser Art der Verzweigung abfragen/auswerten lassen.

Grundgerüst eines Javaprogramms

Da der Programmierer vom Kopieren lebt, schreibt er einmal eine Schablone und benutzt sie immer wieder, frei nach dem Motto: Man muß das Rad nicht zweimal erfinden.


So sieht zum Beispiel ein simples Javaprogramm ohne Handlung aus:


public class Klassenname {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// Anweisungen

	}
}

Erläuterungen: @param ist für das Dokumentationssystem Javadoc, wird im Javakurs vielleicht angesprochen, sollte aber erstmal zweitrangig sein. Dennoch ist Dokumentation wichtiger als der eigentliche Code und deshalb hier erwähnt.


Funktionen (Methoden)

In Java programmiert man meistens Objektorientiert, es sei denn man belegt Info2. Funktionen heißen bei Java Methoden und Methoden sind Objekten zugeordnet, es sei denn man programmiert nicht Objektorientiert. Eine Methode hat immer folgenden Aufbau:

Spezialoption Veröffentlichungsart Rückgabewert Funktionsname ( Parametertyp Parametername ) {

   Methodenrumpf_mit_Anweisungen;

}

Spezialoption:

  • static
  • final

Veröffentlichungsart:

  • public
  • protected
  • private

"Spezialoption" und "Veröffentlichungsart" werden in Java unter dem Begriff Modifier zusammengefasst. Eine Auflistung der Modifier gibt es hier.

Rückgabewert:

  • sämtliche oben aufgeführte Datentypen
  • eigene Datentypen

Funktionsname:

  • einen für die Funktion bezeichnenden Namen aus Buchstaben, Zahlen und dem Underscore ( _ )
  • darf nicht mit eine Zahl beginnen

Parametertyp:

  • wie Rückgabewert, siehe oben

Parametername:

  • wie Funtionsname, siehe oben

Ausgabe

  • Um Fehler finden zu können oder Ausgaben auf der Konsole zu machen, gibt es in Java print-Funktionen:
System.out.print("Irgend ein String.");

Gibt Irgend ein String. auf der Konsole aus ohne einen Zeilenumbruch.

System.out.println("Noch ein String.");

Gibt Noch ein String. auf der Konsole aus allerdings diesmal mit einem Zeilenumbruch.



Klassen

Einfache Datenklasse

Manchmal braucht man neue Datentypen, zum Beispiel um eine Farbe oder einen Punkt zu speichern und damit arbeiten zu können.

Die kann dann wie folgt aussehen:

Eine Punktklasse

class Punkt{
 int x;
 int y;
}
 

Eine Farbenklasse

class Farbe{
 double rotanteil;
 double gruenanteil;
 double blauanteil;
}
 


Diese beiden Klassen kann man so schon tatsächlich verwenden. Allerdings sind sie alles andere als objektorientiert. Sie sind simple Datencontainer und wenn man sie verwenden will, muss man alles über ihren internen Aufbau wissen, wie folgendes Programm zeigt:


class PundF{

    public static void main(String[] args){
    
        Farbe farbe1 = new Farbe();

        farbe1.rotanteil = 0.5;
        farbe1.blauanteil = 0.5;
        farbe1.gruenanteil = 0.5;

        Punkt p = new Punkt();

        p.x=123;
        p.y=321;
    }

}
 


Das ist nicht sehr praktisch, weil man sich vorstellen kann, dass man die Implementierung, also den internen Aufbau z.B. des Punktes, ändern muss. Vielleicht verwendet man statt der kartesischen Koordinaten nun Polarkoordinaten, oder man muss die Farben in einem anderen Farbraum speichern.


Damit jemand, der diese Klassen benutzt, sich nicht darum kuemmern braucht, wie die Daten intern gespeichert werden, benutzt man zum Zugriff auf die Daten sogenannte getter- und setter-Methoden:


Eine bessere Punktklasse - getter und setter

Man kann die Punktklasse nun wie folgt erweitern:

class Punkt{
   private int x;
   private int y;

   public int getX(){
    return this.x;
   }
   public int getY(){
    return this.y;
   }

   public void setX(int arg){
    this.x = arg;
   }
   public void setY(int arg){
    this.y = arg;
   }

}
 

Huch - was soll denn dieses ganze private und public ploetzlich?!

Eigentlich ist das relativ einfach. Die Daten haben wir private deklariert, dass heisst, wir dürfen nur noch innerhalb unserer Klasse darauf zugreifen. Damit wird verhindert, dass jemand von aussen versucht direkt auf die x-Koordinate zuzugreifen, die ja vielleicht irgendwann gar nicht mehr direkt vorhanden ist, wenn wir Polarkoordinaten verwenden:

Punkt mit Polarkoordinaten

class Punkt{
   private double length;
   private double angle;

   public int getX(){
    return ...
   }
   public int getY(){
    return ...
   }

   public void setX(int arg){
    this.length = ... 
   }
   public void setY(int arg){
    this.angle = ...
   }

}
 


Der Vorteil: Alle anderen Programmteile und Klassen koennen wie bisher mit Hilfe der Getter und Setter an die X und Y-Koordinaten kommen, obwohl intern nur Polarkoordinaten vorliegen. Dieses Beispiel ist nicht vollständig, die Mathematik wurde absichtlich weggelassen um Verwirrung zu verhindern ;) [Ausserdem braucht man fuer die Überführung in Polarkoordinaten immer x und y Werte, hat den Sonderfall, dass x nicht 0 sein darf, etc...]


Konstruktor

Ein Konstruktor ist eine besondere Methode, die beim erzeugen eines neuen Objektes (aus einer Klasse) aufgerufen wird. Damit kann man Variables initialisieren/mit Werten vorbelegen, etc.

Für unsere Punktklasse sieht ein Konstruktor zum Beispiel so aus:

...
public Punkt(int x, int y){
    this.x = x;
    this.y = y;
}   
...
 

Das Schluesselwort this bringt damit zum Ausdruck, dass wir nicht auf die Parameter des Konstruktors zugreifen wollen, sondern auf die Attribute dieser (this) Klasse.

Im Zusammenhang sieht das dann wie folgt aus:

class Punkt{
   private int x;
   private int y;

   // Konstruktor:
   public Punkt(int x, int y){
    this.x = x;
    this.y = y;
   }   

   public int getX(){
    return this.x;
   }
   public int getY(){
    return this.y;
   }

   public void setX(int arg){
    this.x = arg;
   }
   public void setY(int arg){
    this.y = arg;
   }

}
 

Die Anwendung ist ebenfalls relativ einfach:

   ...
   Punkt p = new Punkt(5,5);
   Punkt ursprung = new Punkt(0,0);
   ...
 

Komplexere Klasse

Java ist ja eine Objektorientierte Sprache, bzw. unterstützt Objektorientiertes Programmieren. Wodurch zeichnet sich das aus?

Ein Effekt ist, dass eine Klasse alles mitbringt, um mit ihr zu arbeiten, man als Anwender aber nichts über die Innereien der Klasse wissen muss.

Im folgenden soll eine Klasse vorgestellt werden, die ein Postpaket darstellt.


class Postpaket{

  private int breite;  // in cm
  private int hoehe;   // in cm
  private int tiefe;   // in cm

  private int gewicht; // in Gramm

  // Kontruktor, um beim erzeugen eines Paketes
  // direkt alle Werte vorzubelegen
  public Postpaket(int breite, int hoehe, int tiefe){
      this.breite = breite;
      this.hoehe  = hoehe;
      this.tiefe  = tiefe;
  }

  public int getWeight(){
      return this.gewicht;
  }

  public void setWeight(int weight){
      this.gewicht = weight;
  }

  // groesse in Kubikzentimeter
  public int getVolume(){
      return this.breite * this.hoehe * this.tiefe;
  }


  // spezifisches Gewicht in Gramm Pro Kubikzentimeter
  public double getSpecSize ()
  {
    // wir muessen hier vol als double sichern, da sonst
    // von Java automatisch eine Integer-Division
    // durchgeführt wird, so dass die Nachkommastellen abgeschnitten werden!
    double vol = ( this.breite * this.hoehe * this.tiefe);
    return (this.gewicht / vol );
  }



}
 


Wie verwendet man diese Klasse nun?

class Programm{

    public static void main(String[] args){

        Postpaket paket = new Postpaket(340,123,240);
        
        paket.setWeight(1420);

        // wir haben jetzt ein Paket mit Gewicht...

        System.out.println("Das spezifische Gewicht des Pakets: " + paket.getSpecSize());
        System.out.println("Das Volumen des Pakets            : " + paket.getVolume());
    }

}
 


FAQ & Werkzeugkasten

Wie kann man den Benutzer nach einer Eingabe fragen?

Die ist ganz einfach mit der Terminal-Klasse möglich. Möchte man zum Beispiel einen Integerwert einlesen, so schreibt man:

int userInput = Terminal.readInt();

Wenn man dem Benutzer noch eine Aufforderung geben möchte, was er genau eingeben soll, so ist dies mit askInt() möglich:

int age = Terminal.askInt("Please enter your age:");

Natürlich lassen sich auch andere Typen als Integer einlesen, für double und String würde der Code so aussehen:

double money = Terminal.readDouble();
String name = Terminal.readString();

Um die Terminal-Klasse nutzen zu können, muss diese in den gleichen Ordner kopiert werden, in dem sich auch euer Javacode befindet.

Download der Klasse Terminal [1].

Wie kann ich eine Datei einlesen?

Das Einlesen von Dateien gestaltet sich in Java etwas komplizierter. Wir haben euch aus diesem Grunde hier, ähnlich wie bei der Terminaleingabe, eine Bibliotheksklasse gebaut, die euch ein wenig Arbeit abnimmt.

http://docs.freitagsrunde.org/Veranstaltungen/javakurs_2007/vorgaben/EasyFileAccess.java

Mit Hilfe der Funktion getFileContent(String filename) könnt ihr so den Inhalt einer kompletten Datei in ein String-Array lesen, wobei ein Feld im Array jeweils eine Zeile im Text darstellt:


  String[] textContent = EasyFileAccess.getFileContent("Dateipfad");


Häufige Fehlermeldungen

Wir haben eine kleine Übersicht an Fehlern zusammengestellt, die häufig auftreten und mögliche Lösungsmöglichkeiten dafür beschrieben.


Wozu ist der Stringarray args in der Mainmethode gut?

In args werden alle Parameter gespeichert, die euer Javaprogramm beim Aufruf aus der Konsole uebergeben bekommt. D.h. wenn ihr

java ExampleProgram -h test

aufruft, dann wird in args[0] "-h" und in args[1] "test" gespeichert. Ihr koennt Parameter dann so auslesen (mit Integer.parseInt() kann man Strings in Integer umwandeln):

public class Parameter {
   public static void main(String[] args) {
      if (args.length >= 1) {
          // wandel den String args[0] in eine Zahl um
          int parameter = Integer.parseInt(args[0]);
          System.out.println("the first parameter is: "+parameter);
      } else {
          System.out.println("usage: java Parameter NUMBER");
      }
   }
}


Wie kann ich mit Java eine Grafik zeichnen?

Genau fuer diesen Zweck gibt es die Klasse Pad.java, die wie die Terminalklasse von Pepper bereitgestellt wird. Zusaetzlich benoetigt ihr allerdings noch die Point.java.


Lege die Dateien in dem Verzeichnis ab, in dem auch dein Programm entstehen soll. Wenn du dies getan hast, steht dir die Grafikfunktionalität zur Verfuegung.

//Mit
Pad drawPad = new Pad();
//wird ein neues Fenster erzeugt.

drawPad.setPadSize(int width, int height);
//setzt die Größe des Fensters.

drawPad.setVisible(true);
//zeigt das Fenster an.

drawPad.drawDot(int x, int y);
//zeichnet einen Punkt an der Stelle (x,y).

Du musst noch nicht verstehen, was dies sprachlich genau bedeutet. In Vorträgen 5 und 6 sollte dann klar werden was, drawPad genau ist.