Zum Hauptinhalt

Grundlegendende Programmierkonzepte in Java

Website: Hamburg Open Online University
Kurs: Programmieren mit Java
Buch: Grundlegendende Programmierkonzepte in Java
Gedruckt von: Gast
Datum: Donnerstag, 21. November 2024, 14:06

Beschreibung

Hier lernst du die grundlegenden Konzepte kennen und hast die Möglichkeit, dies als Tagebuch festzuhalten.

Ein Tagebuch

Bevor wir den Einstieg in die Programmierung mit Java starten, sollten wir uns einmal überlegen, wo die Reise hingehen soll. Es wäre doch eine wirklich gute Sache, wenn man ein Werkzeug hätte, mit dem man das Programmieren lernen kann und gleichzeitig den Fortschritt auch dokumentieren kann. Um hier ein nützliches Projekt zum Anfangen zu haben, wollen wir uns ein Tagebuch aufbauen. Ein Tagebuch aber nicht einfach nur als Text-Dokument in das wir nur hineinschreiben können, sondern als ein Programm, welches uns hilft die Daten zu verwalten und ggF. später auch vor unbefugtem Zugriff zu schützen und grafisch ansprechend darzustellen.

Die Erste Version unseres Tagebuches soll etwas dynamischer sein als unser vorheriges Programm dass immer nur “Hallo Welt!” ausgegeben hat. Im Erste Schritt wollen wir hierfür eine Variable “name” mit dem Datentyp “String” einführen, in der später der Name das Benutzers abgelegt werden kann.

Mit dem Datentyp String können Zeichenfolgen (Wörter, Sätze und ganze Texte) gespeichert werden.


public class Tagebuch { public static void main(String[] args) { String name = "Jan"; System.out.println("Hallo " + name + "!"); } }

Variablen

Variablen sind Speicherbereiche, in die Werte gespeichert werden können, während das Programm läuft. Wird das Programm beendet, so gehen die Werte verloren.

In Java muss jede Variable vor der ersten Verwendung deklariert werden. Dabei wird ihr ein Datentyp und ein Name zugeordnet. In unserem Beispiel oben wird auch gleich noch ein Wert zugewiesen.


Datentyp variable = Wert;

Man kann die Variable auch erst deklarieren und später beliebig oft Werte zuweisen.


Datentyp variable;
 variable = Wert;                   
Der Datentyp String

Strings werden in doppelten Anführungszeichen ("“) geschrieben. Der kürzeste String ist”" und enthält keine Zeichen.

Um zwei String zu verbinden kann der + Operator verwendet werden.


String s = "Hallo " + " Welt!";

Ein- und Ausgabe

Noch haben wir kein wirklich dynamisches Programm. Es erzeugt noch immer eine Ausgabe, die sich nur während der Programmierung und nicht während der Laufzeit ändern lässt. Das wollen wir jetzt ändern. Ziel ist es einen Dialog zur Ein- und Ausgabe von Daten zu erstellen.

Hierfür bietet Java unter anderem sogenannte Scanner an. Ein Scanner kann aus sogenannten InputStreams zeilenweise lesen. Für unser Beispiel wollen wir den InputStream System.in verwenden. Dieser nimmt die Eingaben aus der Konsole entgegen, in der das Programm ausgeführt wird. Das Gegenstück zu System.in ist System.out. System.out ist ein sogenannter OutputStream. Genau genommen der OutputStream, der in die Konsole führt in der das Programm gestartet wurde.

Um den Scanner verwenden zu können, müssen wir ihn wieder als erstes als Variable deklarieren und danach initialisieren. Zur Initialisierung von Objekten wird in Java das Schlüsselwort “new” verwendet und danach eine Methode aufgerufen, die genau wie der Typ heißt. Wir schreiben also Scanner scanner = new Scanner(System.in);

Nach der Initialisierung ist der Scanner bereit zur Verwendung. Mit der Methode scanner.next() kann jetzt eine Zeile von der Konsole gelesen werden. Wird die Methode aufgerufen, so wartet das Programm auf Eingaben des Benutzers und wird erst fortfahren, wenn der Benutzer die Eingabe mit Enter bestätigt. Die Methode gibt die Zeile als String zurück.

Als vollständiges Beispiel ergibt sich:


import java.util.Scanner; public class Tagebuch { public static void main(String[] args) { System.out.println("Wie heißt du?"); Scanner scanner = new Scanner(System.in); String name = scanner.next(); scanner.close(); System.out.println("Hallo " + name + "!"); } }
Das Schlüsselwort new

Durch das Schlüsselwort new wird Java angewiesen ein neues Objekt zu erstellen. Man spricht auch davon, dass eine Instanz erzeugt wird. Durch den new Aufruf reserviert Java den nötigen Speicherbereich für das Objekt. Es bekommt jedes Objekt immer seinen eigenen Speicherbereich. So kann man z.B. zwei Objekte vom Typ String erzeugen. Auch wenn diese das gleiche Wort speichern, liegen diese an zwei unterschiedlichen Stellen im Speicher und könnten unabhängig von einander verändert werden.

Objekte gehören immer einem Typ an. Der Name des Types muss daher schon bei der Instanziierung benötigt.

Die Erzeugung von Strings ist hier eine Besonderheit. Die kurze Schreibweise "Hallo" wird vom Compiler verstanden als


new String ("Hallo")

Es wird also jedes Mal ein eigener Speicherbereich für die Zeichenkette reserviert.

Der Scanner

Scanner bieten die Möglichkeit Text zeilenweise einzulesen. Um einen Scanner zu initialisieren muss muss ein eine neue Instanz erzeugt werden. Zusätzlich muss ein InputStream (z.B. System.in) als Datenquelle übergeben werden.

Durch die Methode next() wird der Programmablauf blockiert bis eine Zeile eingegeben wurde. Die eingegebene Zeile wird dann zurück gegeben.

Die Methode close() teilt Java mit, dass aus dem Scanner nicht mehr gelesen werden soll und dieser geschlossen werden kann.

Das Schließen des Scanners ist in unserem Beispiel eigentlich nicht erforderlich. Es ändert nichts. Dennoch ist es eine gute Praxis die close-Methoden zu verwenden, wenn ein Datentyp diese anbietet und das jeweilige Objekt ausgebraucht ist. Erst hierdurch wird Java mitgeteilt, dass die verwendete Eingabe-Ressource nicht mehr gebraucht wird. Java gibt dann die Ressource frei und entlastet damit das Betriebssystem, welches die Ressource sonst weiter bereitstellen müsste. In unserem Beispiel ist das noch nicht kritisch, da mit dem Beenden des Programms ohnehin alle Ressourcen freigegeben werden.

Ablaufsteuerung

Die Ausgabe unseres Programms kann jetzt schon durch den Benutzer gesteuert werden. Der Ablauf ist aber immer der Gleiche. Als nächstes wollen wir auch den Programmablauf steuern.

If

Die Ausgabe unseres Programms kann jetzt schon durch den Benutzer gesteuert werden. Der Ablauf ist aber immer der Gleiche. Als nächstes wollen wir auch den Programmablauf steuern. Als erstes wollen wir hierfür die Kontrollstruktur if verwenden. Der grundlegende Aufbau eines if Ausdrucks ist:

if( Wahrheitsaussage ) { Anweisung; }

Die Wahrheitsaussage ist ein Ausdruck, der nur wahr oder falsch sein kann. Im Englischen true oder false. Es gibt den Datentyp boolean für Wahrheitsaussagen. Als Anweisung kann z.B. eine oder mehrere Methoden aufgerufen werden.

Es gibt unendlich viele Möglichkeiten, wie man eine Wahrheitsaussage erzeugen kann. Wir wollen als erstes mit einem Vergleich beginnen. Der Vergleich soll sein, ob die Eingabe des Benutzers ein Bestimmtes Wort gewesen ist. Hierfür bietet der Datentyp String die Methode equals.

Unser vorheriges Beispiel können wir nun so erweitern, dass nur eine von uns definierte Person begrüßt wird.


import java.util.Scanner; public class Tagebuch { public static void main(String[] args) { System.out.println("Wie heißt du?"); Scanner scanner = new Scanner(System.in); String name = scanner.next(); scanner.close(); if(name.equals("Jan")) { System.out.println("Hallo " + name + "!"); } } }

Else

Wenn jetzt eine Andere Person das Programm verwendet, so wird sie nicht begrüßt. Es geschieht einfach garnichts. Es hat sich gezeigt, dass die Anwender eines Programms sich wundern, wenn etwas geschieht, was sie nicht erwarten. Besonders genervt sind sie aber meistens, wenn das Programm ihnen nicht einmal die Möglichkeit gibt das Problem nachzuvollziehen. Aus diesem Grund sollten wir das Programm etwas erweitern. Mit Hilfe der else Struktur können wir alles abgelehnten Benutzern dieses mitteilen. Ein Else kann immer nur in Verbindung mit einem Vorangegangenen If stehen. Der Aufbau ist dann:


 if( Wahrheitsaussage ) {
     Anweisung;
 } else {
     AlternatiiveAnweisung;
 }    

Java führt jetzt die Erste Anweisung aus, wenn die Wahrheitsaussage wahr ist und wenn sie falsch ist, wird die alternative Anweisung ausgeführt. Unser Beispiel kann entsprechend erweitert werden:



 if(name.equals("Jan")) {
     System.out.println("Hallo " + name + "!");
 } else {
     System.out.println("Der Benutzer ist abgelehnt.");
 }   

Es muss hinter dem Schlüsselwort else nicht direkt ein Block geschrieben werden. Es ist auch möglich mehrere If miteinander zu verbinden:


 if( Wahrheitsaussage ) {
     Anweisung1;
 } else if( ZweiteWahrheitsaussage ) {
     Anweisung2;
 } else if( DritteWahrheitsaussage ) {
     Anweisung3;
 } else {
     AlternatiiveAnweisung;
 }    

Hierbei muss man wissen, dass nur die Anweisungen des ersten If mit wahrer Aussage ausgeführt werden. Ist keine der Aussagen wahr, so werden die Anweisungen des Else ausgeführt.

Welche Ausgaben erzeugen die folgenden beiden Programmauszüge? 


 
String tier = "Katze"; if( tier.equals("Katze") ) { System.out.println("Katzen sind niedlich"); } else if( tier.equals("Katze") ) { System.out.println("Katzen fressen Mäuse"); } else { System.out.println("Alles außer Katzen"); }

Variante 2:

 
String tier = "Katze"; if( tier.equals("Katze") ) { System.out.println("Katzen sind niedlich"); } if( tier.equals("Katze") ) { System.out.println("Katzen fressen Mäuse"); } else { System.out.println("Alles außer Katzen"); }
If, Else und Else-if

Durch die If-Struktur kann die Ausführung eines Programmabschnitts an eine Bedingung geknüpft werden.

if( Wahrheitsaussage ) { Anweisung; }

Wollen wir ein Entweder-Oder darstellen, so können wir ein If mit einem Else verbinden.


 if( Wahrheitsaussage ) {
     Anweisung;
 } else {
     AlternatiiveAnweisung;
 }

Wir können aber auch mehrere Ifs miteinander verbinden, so dass der Code der ersten erfüllten Bedingung ausgeführt wird. Hierfür verwendet man das Else-If.

 
 if( Wahrheitsaussage ) {
     Anweisung1;
 } else if( ZweiteWahrheitsaussage ) {
     Anweisung2;
 } else {
     AlternatiiveAnweisung;
 }   

While

Die nächste Erweiterung unseres Programms soll nun sein, dass Anweisungen mehrfach ausgeführt werden. Natürlich könnten wir dafür viele Male das selbe schreiben. Es geht aber auch sehr viel einfacher. Mit Hilfe der while-Schleife können wir bestimmen, dass ein Teil unseres Programms wiederholt wird. Der Aufbau von While ist sehr ähnlich zu dem des If:


 while( Wahrheitsaussage ) {
     Anweisung;
 }    
Wenn Java im Programmablauf eine While erreicht, prüft es als Erstes, ob die Wahrheitsausage wahr ist. Wenn nicht werden die Anweisungen übersprungen. Sollte die Aussage wahr sein, so wird der Anweisungsblock ausgeführt. Ist das Ende erreicht, so springt Java wieder an den Anfang der While-Schleife und beginnt von Neuem.

Was würde jetzt aber passieren, wenn der Wahrheitsausdruck immer wahr wäre? Java würde in diesem Fall für immer vom Ende der Schleife wieder zum Anfang springen. Wir hätten eine Endlosschleife. Das Programm läuft dann also bis es vom Betriebssystem beendet wird. Hierfür haben wir in Eclipse ein Button in Form eines roten Quadrats.

Wir wollen nun unser Programm so erweitern, dass der Benutzer mehrere Zeilen Text eingeben kann und wir diesen in einer Variable speichern. Durch Eingabe des Wortes “quit” soll das Programm den Ganzen Text ausgeben und sich dann beenden.

Bevor wir das umsetzen können, müssen wir aber noch klären, wie wir eine Aussage verneinen. Hierfür hat Java das Ausrufungszeichen reserviert. Wir können also schreiben


 while( ! text.equals("quit")) {} 

um auszudrücken, dass nur die Eingabe “quit” zu einem Abbruch führen soll.


import java.util.Scanner; public class Tagebuch { public static void main(String[] args) { System.out.println("Wie heißt du?"); Scanner scanner = new Scanner(System.in); String name = scanner.next(); if(name.equals("Jan")) { System.out.println("Hallo " + name + "!"); String text = ""; String eingabe = scanner.next(); while( ! eingabe.equals("quit") ) { text = text + eingabe; eingabe = scanner.next(); } System.out.println("Eingegeben wurde: " + text); } else { System.out.println("Der Benutzer ist abgelehnt."); } scanner.close(); } }

Es ich wichtig, dass wir als letzte Anweisung im Block der While-Schleife wieder eine Zeile Text einlesen. Würden wir dies vergessen, so hätten wir eine Endlosschleife.

Durch die Anweisung text = text + eingabe; wird die Eingabe an den zwischengespeicherten Text hinten angehängt. Dies funktionier, weil Java erst den rechten Teil also text + eingabe ausführt und erst danach das Ergebnis in die Variable text speichert. Es kommt sehr oft vor, dass man an eine Variable etwas anhängen möchte. Aus diesem Grund hat Java hierfür eine Kurzschreibweise 

text += eingabe;


While

Mit der While-Schleife wird ein Codeblock mehrfach ausgeführt.

 while( Wahrheitsaussage ) {
    Anweisung;
 }             

 ! (Nicht) Operator

Durch den Nicht-Operator “!” wird eine Aussage in das Gegenteil verwandelt. Der Operator wird vor die Aussage geschrieben.

Wir wollen uns noch eine andere Schreibweise anschauen, die genau das selbe ergebnis bring. Hierfür bauen wir die Schleife so um, dass sie immer wieder von vorne beginnt while(true){...}. Jetzt können wir in der Schleife den Text einlesen und sollte die Eingabe “quit” sein, so verlassen wir die Schleife mit dem Schlüsselwort break. Das geänderte Beispiel ist dann:


Scanner scanner = new Scanner(System.in); String text = ""; while (true) { String eingabe = scanner.next(); if(eingabe.equals("quit")) { break; } text += eingabe + "\n"; }
Break und Continue

Die Anweisung Break kann nur in einer Schleife verwendet werden. Durch sie wird Java aufgefordert die Schleife sofort zu verlassen. Alle Anweisungen, die im Schleifen-Block noch folgen, werden nicht mehr ausgeführt. Außerdem wird nicht wieder von vorne begonnen. Genau hier liegt der Unterschied zu der Anweisung Continue. Auch durch Continue wird der Rest des Schleifen-Blocks nicht mehr ausgeführt aber es wird erneut geprüft ob die Wahrheitsaussage noch wahr ist und die Schleife erneut ausgeführt werden kann.

Wir sollten an dieser Stelle noch auf eine mögliche Fehlerquelle. Im vorherigen Beispiel wurde die Variable “text” vor der Schleife deklariert. Das ist sehr wichtig, dann Variablen in Java existieren nur in dem Block in dem sie deklariert wurden und in Blöcken, die mit in ihrem eingebettet sind. Aus diesem Grund kann die Variable “text” auch in der Schleife verwendet werden. Wir sprechen hierbei vom Scope der Variable.

Die Variable “eingabe” existiert nur in dem Block der Schleife. Sie wir bei jedem Schleifendurchlauf neu deklariert und kann außerhalb des Schleifen-Blocks nicht verwendet werden.

Bei dem Einlesen einer Zeile mit scanner.next() wird das Zeilenende-Zeichen entfernt. Aus diesem Grund wird in dem Beispiel wieder ein Zeilenumbruch ("\n") angehängt. Zeilenumbrüche werden von Computern als normale Zeichen behandelt. Es gibt aber keine Taste und keine richtige Darstellung für diese Zeichen, darum werden sie im Quellcode durch zwei Zeichen dargestellt.

Mitlerweile ist der Quelltext schon etwas angewachsen und wir sollten uns langsam Gedanken über die Lesbarkeit machen. Einen Punkt der Lesbarkeit, die Einrückung, hatten wir bereits besprochen. Dieser Punkt ist so wichtig, dass Eclipse hierfür einen Automatismus bereitstellt. Durch die Tastenkombination Strg + Umschalt + F wird der Code automatisch formatiert. Die Einrückung ist wieder gerettet.

Einweiterer Aspekt der Lesbarkeit sind Kommentare. Kommentare sind Anmerkungen für den Programmier. Sie ändern das Verhalten des Programms nicht sondern werden vom Compiler ignoriert. Mit den Zeichen // wird alles, was bis Zum Ende einer Zeile folgt zu einem Kommentar. Alternativ können auch Blockkommentare /* Mehrere Zeilen Text */ geschrieben werden. Wie viel man kommentiert ist jedem selbst überlassen. Es empfiehlt sich aber, regelmäßig zu notieren warum man etwas gemacht hat. Was genau an einer Stelle geschieht, braucht man selten kommentieren, da dies ja durch den Quelltext dokumentiert ist. Unser Beispiel könnte mit Kommentaren wie folgt ergänzt werden:


 import java.util.Scanner;

 public class Tagebuch {

     public static void main(String[] args) {

         System.out.println("Wie heißt du?");

         Scanner scanner = new Scanner(System.in);

         String name = scanner.next();

         if (name.equals("Jan")) {
             System.out.println("Hallo " + name + "!");
             System.out.println("Bitte Text eingeben. Zum Beenden 'quit' eingeben.");

             // Schleife zum Einlesen des Textes
             String text = "";
             while (true) {
                 String eingabe = scanner.next();

                 // "quit" soll das Ende der Eingabe signalisieren
                 if (eingabe.equals("quit")) {
                     break;
                 }

                 text += eingabe + "\n";
             }

             System.out.println("Eingegeben wurde: " + text);

         } else {
             System.out.println("Der Benutzer ist abgelehnt.");
         }

         scanner.close();
     }
 } 

For

Die for-Schleife ist eine verkürzte Schreibweise einer while-Schleife, die immer dann eingesetzt werden kann, wenn es darum geht eine bestimmte Anzahl an wiederholungen zu machen. Bevor wir uns mit der for-Schleife beschäftigen können brauchen wir aber noch einen neuen Datentyp mit dem wir Zahlen darstellen können. Hierfür ist der Typ int am gebräuchlichsten. Mit ihm können ganze Zahlen gespeichert werden. Es ist möglich mit dem Operator <, zu prüfen, ob eine Zahl kleiner ist als eine Andere und zwei Zahlen können mit dem + Operator addiert werden. Das soll uns ersteinmal genügen. Weitere Zahlen-Datentypen und Operatoren sind im nächsten Abschnitt beschrieben.

Mit unserem neuen Datentyp und Operatoren können wir jetzt z.B. eine Reihe von Zahlen ausgeben. 


int zahl = 1; while (zahl < 11) { System.out.println(zahl); zahl = zahl + 1; }

Genau hier liegt dann auch der Vorteil der for-Schleife gegenüber der while-Schleife. Das obige Beispiel lässt sich, mit ihr, sehr viel lesbarer schreiben:


for(int zahl = 1; zahl < 11; zahl = zahl + 1) { System.out.println(zahl); }

Es können also drei Anweisungen in der for-Schleife zusammengefasst geschrieben werden. Dabei muss die erste Anweisung eine Deklaration oder Initialisierung sein. Es wird die Laufvariable deklariert und initialisiert. Die zweite Anweisung ist die Wahrheitsaussage, wie wir sie aus der While-Schleife kennen. In der dritten Anweisung kann dann die Laufvariable verändert werden. Die erste und letzte Anweisung dürfen auch leer sein. Beispielsweise wäre for(; true; ) {} wieder eine Endlosschleife.

For

Mit der For-Schleife kann die Anzahl der Wiederholungen eines Codeblocks einfach angegeben werden.


for(Initialisierung; Wahrheitsaussage; Variablenmanipulation) { Anweisung; }