19
Kapitel 4 Tag 3: Daten laden und speichern In vielen Fällen ist es erforderlich, in Dateien vorliegende Daten für die Ausführung eines Programms zu ver- wenden. Es könnte z.B. eine Datei vorliegen in der die Namen, Matrikelnummern und erreichten Punkte bei den Übungszettel gespeichert sind und es stellt sich die Frage, wer von den Studenten nun die Zulassung für die Klausur erworben hat. Ebenso ist es oft erforderlich berechnete Daten nicht nur in der Konsole auszugeben, sondern diese in einer Datei abzulegen. Diese beiden Verfahren und die Möglichkeit beim Start eines Javaprogramms Parameter zu übergeben, werden wir im folgenden Kapitel behandeln. 4.1 Externe Programmeingaben Die einfachste Methode meinem Programm ein paar kleine Daten mit auf dem Weg zu geben ist die Übergabe von Parametern auf der Kommandozeile. Wir hatten ja schon gesehen, dass ein Javaprogramm nach der Kompilierung mit C:\>javac MirIstWarm . java C:\>java MirIstWarm aufgerufen und gestartet wird. Wenn z.B. das Programm MirIstWarm.java so aussieht, wird einfach der Text „Mir ist heute zu warm, ich mache nix :).“ ausgegeben. 45

Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

Embed Size (px)

Citation preview

Page 1: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

Kapitel 4

Tag 3: Daten laden und speichern

In vielen Fällen ist es erforderlich, in Dateien vorliegende Daten für die Ausführung eines Programms zu ver-wenden. Es könnte z.B. eine Datei vorliegen in der die Namen, Matrikelnummern und erreichten Punkte bei denÜbungszettel gespeichert sind und es stellt sich die Frage, wer von den Studenten nun die Zulassung für die Klausurerworben hat.

Ebenso ist es oft erforderlich berechnete Daten nicht nur in der Konsole auszugeben, sondern diese in einer Dateiabzulegen. Diese beiden Verfahren und die Möglichkeit beim Start eines Javaprogramms Parameter zu übergeben,werden wir im folgenden Kapitel behandeln.

4.1 Externe Programmeingaben

Die einfachste Methode meinem Programm ein paar kleine Daten mit auf dem Weg zu geben ist die Übergabe vonParametern auf der Kommandozeile. Wir hatten ja schon gesehen, dass ein Javaprogramm nach der Kompilierungmit

C: \ > j a v a c MirIstWarm . j a v aC: \ > j a v a MirIstWarm

aufgerufen und gestartet wird. Wenn z.B. das Programm MirIstWarm.java so aussieht, wird einfach der Text „Mirist heute zu warm, ich mache nix :).“ ausgegeben.

45

Page 2: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN

1 / / MirIstWarm . j a v a2 p u b l i c c l a s s MirIstWarm {3 p u b l i c s t a t i c vo id main ( S t r i n g [ ] a r g s ) {4 System . o u t . p r i n t l n ( "Mir ist heute zu warm , ich mache nix :)." ) ;5 }6 }

In Zeile 3 sehen wir den Parameter String[] args, er steht für solche Fälle zur Verfügung, in denen wir demProgramm einen oder mehrere Parameter vor dem Start mitgeben wollen. Ein Beispiel, an dem klar wird, wie esfunktioniert:

C: \ > j a v a c MeineEingaben . j a v aC: \ > j a v a MeineEingaben H a l l o 27Eingabe 1 : >Hal lo < undEingabe 2 : >27<

Das Programm MeineEingaben.java gibt nun aus, welche Eingaben es erhalten hat:

1 / / MeineEingaben . j a v a2 p u b l i c c l a s s MeineEingaben {3 p u b l i c s t a t i c vo id main ( S t r i n g [ ] a r g s ) {4 System . o u t . p r i n t l n ( "Eingabe 1: >"+ a r g s [ 0 ] + "< und" ) ;5 System . o u t . p r i n t l n ( "Eingabe 2: >"+ a r g s [ 1 ] + "<" ) ;6 }7 }

In diesem Fall war es wichtig zu wissen, wieviele Eingaben wir erhalten haben. Sollten wir auf einen Eintrag inder Stringliste args zugreifen, die keinen Wert erhalten hat, dann passiert folgendes:

C: \ > j a v a MeineEingaben H a l l oE x c e p t i o n i n t h r e a d " main " j a v a . l a n g . Ar ray IndexOutOfBoundsExcep t ion : 1

a t MeineEingaben . main ( MeineEingaben . j a v a : 5 )

Wir erhalten also eine Fehlermeldung mit dem Hinweis „ArrayIndexOutOfBoundsException“. Wir haben also inZeile 5 auf einen Index zugegriffen, der nicht existiert und damit einen Fehler verursacht. Wir könnten das Problemnun mit folgenden zusätzlichen Zeilen so umgehen:

1 / / MeineEingaben . j a v a2 p u b l i c c l a s s MeineEingaben {3 p u b l i c s t a t i c vo id main ( S t r i n g [ ] a r g s ) {4 f o r ( i n t i =0 ; i < a r g s . l e n g t h ; i ++)5 System . o u t . p r i n t l n ( "Eingabe "+ i +": >"+ a r g s [ i ]+"<" ) ;6 }7 }

Nun überprüfen wir vor der Ausgabe die Anzahl der Elemente und gehen sie einfach in einer Schleife durch undgeben sie aus, dann funktioniert es auch für beliebige Eingaben:

C: \ > j a v a MeineEingaben H a l l o 27 und noch v i e l mehr !Eingabe 0 : >Hal lo <Eingabe 1 : >27<Eingabe 2 : >und <Eingabe 3 : >noch <Eingabe 4 : > v i e l <Eingabe 5 : >mehr ! <

Nun sind wir also in der Lage von außen unterschiedliche Parameter an unser Programm zu geben, ohne es jedesmalneu kompilieren zu müssen.

Page 3: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

4.2. DATEN AUS EINER DATEI EINLESEN 47

4.2 Daten aus einer Datei einlesen

Wenn wir es aber mit der Verwaltung einer Datenbank zu tun haben, wollen wir nicht über die Kommandozeiledie vielen Daten übergeben. Wir können die Daten aus einer Datei lesen. Es gibt viele Möglichkeiten in Java, wieman das bewerkstelligen kann. Ich zeige hier einfach mal eine, es sei dem Leser aber überlassen eine andere zuverwenden. Obwohl wir die Begriffe Objektorientierung, Klassen, usw. erst in Abschnitt ... behandeln werden,müssen wir hier auch schon externe Klassen und deren Funktionen verwenden. Das soll uns aber nicht weiterstören, wir sehen an einem Beispiel, wie einfach es funktioniert.

1 import j a v a . i o . ∗ ;2 p u b l i c c l a s s L i e s D a t e i E i n {3 p u b l i c s t a t i c vo id main ( S t r i n g [ ] a r g s ) {4 / / Date iname wird übe rgeben5 S t r i n g f i l e n a m e I n = a r g s [ 0 ] ;6 t r y {7 F i l e I n p u t S t r e a m f i s = new F i l e I n p u t S t r e a m ( f i l e n a m e I n ) ;8 I n p u t S t r e a m R e a d e r i s r = new I n p u t S t r e a m R e a d e r ( f i s ) ;9 B u f f e r e d R e a d e r bur = new B u f f e r e d R e a d e r ( i s r ) ;

10

11 / / d i e e r s t e Z e i l e wi rd e i n g e l e s e n12 S t r i n g s L i n e = bur . r e a d L i n e ( ) ;13

14 / / l i e s a l l e Z e i l e n aus , b i s k e i n e mehr vorhanden s i n d15 i n t z a e h l e r = 0 ;16 whi le ( s L i n e != n u l l ) {17 System . o u t . p r i n t l n ( "Zeile "+ z a e h l e r +": "+ s L i n e ) ;18 s L i n e = bur . r e a d L i n e ( ) ;19 z a e h l e r ++;20 }21

22 } ca tch ( Ar ray IndexOutOfBoundsExcep t ion eAIOOB ) {23 System . o u t . p r i n t l n ( "Brauche einen Dateinamen als Parameter" ) ;24 } ca tch ( IOExcep t ion eIO ) {25 System . o u t . p r i n t l n ( "Konnte Datei "+ f i l e n a m e I n +" nicht öffnen!" ) ;26 }27 }28 }

Verwenden könnten wir LiesDateiEin.java nun z.B. mit der Datei namen.dat. Den Inhalt einer Datei kann mansich auf der Konsole mit dem Befehl type anschauen...

C: \ > t y p e namen . d a tH a r a l d LiebchenGustav P e t e r s o nGunnar HeinzePau l F r e u n d l i c h

C: \ > j a v a L i e s D a t e i E i n namen . d a tZ e i l e 0 : H a ra ld L iebchenZ e i l e 1 : Gustav P e t e r s o nZ e i l e 2 : Gunnar HeinzeZ e i l e 3 : Pau l F r e u n d l i c h

Unser Programm kann eine Datei zeilenweise auslesen und gibt das eingelesene gleich auf der Konsole aus.

4.3 Daten in eine Datei schreiben

Um eine Datei zu speichern, schauen wir uns mal folgendes Programm an:

Page 4: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

48 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN

1 import j a v a . i o . ∗ ;2 p u b l i c c l a s s S c h r e i b e I n D a t e i {3 p u b l i c s t a t i c vo id main ( S t r i n g [ ] a r g s ) {4 / / Date iname wird übe rgeben5 S t r i n g f i l e n a m e O u t p u t = a r g s [ 0 ] ;6 t r y {7 B u f f e r e d W r i t e r myWriter =8 new B u f f e r e d W r i t e r ( new F i l e W r i t e r ( f i l e n a m e O u t p u t , f a l s e ) ) ;9

10 / / s c h r e i b e z e i l e n w e i s e i n d i e D a t e i f i l e n a m e O u t p u t11 myWriter . w r i t e ( "Hans Mueller\n" ) ;12 myWriter . w r i t e ( "Gundel Gaukel\n" ) ;13 myWriter . w r i t e ( "Fred Feuermacher\n" ) ;14

15 / / s c h l i e s s e d i e D a t e i16 myWriter . c l o s e ( ) ;17 } ca tch ( IOExcep t ion eIO ) {18 System . o u t . p r i n t l n ( "Folgender Fehler trat auf: "+eIO ) ;19 }20 }21 }

Nun testen wir mal unser Programm und verwenden zur Überprüfung die vorher besprochene Klasse LiesDatei-Ein.java.

C: \ > j a v a S c h r e i b e I n D a t e i namen2 . d a t

C: \ > j a v a L i e s D a t e i E i n namen2 . d a tZ e i l e 0 : Hans M u e l l e rZ e i l e 1 : Gundel GaukelZ e i l e 2 : Fred Feuermacher

Wir stellen fest. Es hat funktioniert.

4.4 Daten von der Konsole einlesen

Wir sind nun in der Lage Daten in beim Programmstart mitzugeben und Dateien auszulesen, oft ist es aber wün-schenswert eine Interaktion zwischen Benutzer und Programm zu haben. Beispielsweise soll der Benutzer eineEntscheidung treffen oder eine Eingabe machen. Das ist mit dem BufferedReader schnell realisiert:

1 import j a v a . i o . ∗ ;2 p u b l i c c l a s s E i n l e s e n {3 p u b l i c s t a t i c vo id main ( S t r i n g [ ] a r g s ) {4 System . o u t . p r i n t ( "Eingabe: " ) ;5 t r y {6 I n p u t S t r e a m R e a d e r i s r = new I n p u t S t r e a m R e a d e r ( System . i n ) ;7 B u f f e r e d R e a d e r bur = new B u f f e r e d R e a d e r ( i s r ) ;8

9 / / H ie r l e s e n wi r e i n e n S t r i n g e i n :10 S t r i n g s t r = bur . r e a d L i n e ( ) ;11

12 System . o u t . p r i n t l n ( s t r ) ;13 } ca tch ( IOExcep t ion e ) { }14 }15 }

Page 5: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

4.5. ZUSAMMENFASSUNG UND CHECKLISTE 49

Noch ein kleiner Test:

C: \ > j a v a E i n l e s e nEingabe : I c h gebe e twas e i n 4 ,5 a 1 / 2I c h gebe e twas e i n 4 ,5 a 1 / 2

4.5 Zusammenfassung und Checkliste

Zusammenfassung

Checkliste

4 Texte und Zahlen aus beliebigen Dateien einlesen

4 Dateien erstellen und mit Daten füllen

4 Parameter über die Konsole an ein Javaprogramm übergeben

4.6 Aufgaben

Übung 1) Wir haben gesehen was passiert, wenn wir weniger Parameter übergeben (siehe 4.1), als das Programmsie verlangt oder erwartet. Teste wie das Programm reagiert, wenn Du mehr als die gewünschte Anzahl vonParametern übergibst.

Übung 2) Erzeuge mit der Klasse ErzeugeVieleWerte.java eine Datei, die 100 Zeilen á 10 Spalten besitzt und injedem Eintrag folgender Wert steht: Eintrag(Zeile i, Spalte j) = i2 + j.

Übung 3) Schreibe ein Programm, das das Alphabet in Groß- und Kleinbuchstaben nacheinander in eine Datei„Alphabet.dat“ schreibt. Anschliessend soll die Datei eingelesen werden und die Anzahl der enthaltenenBuchstaben gezählt und ausgegeben werden.

Übung 4) Modifiziere Deine Lösungen zu den Fibonaccizahlen und zur Fakultätsberechnung (siehe 3.7) mitfolgenden Eigenschaften:o beide Funktionen werden von der Klasse MeineFunktionen.java angeboteno beim Programmstart wird abgefragt, welche der beiden Funktionen und welcher Startwert verwendet wer-den sollo anschliessend gibt es eine schöne Ausgabeo Die Klasse soll ausreichend kommentiert und den bereits besprochenen Konventionen entsprechen

Page 6: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

50 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN

Page 7: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

Kapitel 5

Tag 4: Verwendung einfacherDatenstrukturen

Bisher haben primitive Datentypen für die Lösung einfacher Probleme ausgereicht. Nun wollen wir uns mit zu-sammengesetzten Datentypen auseinandersetzen, den sogenannten Datenstrukturen. Das Wort Datenstruktur verrätschon, dass wir die Daten in Strukturen zusammenfassen wollen, die bestimmte Eigenschaften besitzen. Diese Ei-genschaften können sich z.B. darin auswirken, dass wir schneller ein bestimmtes Datum finden, oder eine großeDatenmenge platzsparend speichern können (eine gute Referenz zu diesem Thema ist [11]).

Als Einstiegspunkt sind Arrays, die in fast jeder Programmiersprache angeboten werden, geeignet. Wir werden mitHilfe zweidimenionaler Array Conway’s Game of Life implementieren, dazu müssen wir uns zunächst mit derHandhabung der Arrays vertraut machen.

5.1 Arrays und Matrizen

5.1.1 Erzeugung eines Arrays

Fangen wir mit der einfachsten Datenstruktur an. Nehmen wir an, wir möchten nicht nur einen int, sondern vieleint’s verwalten. Dann könnten wir es so bewerkstelligen:

i n t a , b , c , d , e , f ;a =0 ;b =1;c =2;d =3;e =4;f =5 ;

Das ist sehr aufwendig. Einfacher wäre es, wenn wir sagen könnten, dass wir k verschiedene int’s haben und diesedann über einen Index ansprechen können. Genau das nennen wir ein Array. Das besondere an den Arrays ist, dasssie für k Elemente mit dem Index 0 beginnen und mit dem Index k−1 enden.

51

Page 8: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

52 KAPITEL 5. TAG 4: VERWENDUNG EINFACHER DATENSTRUKTUREN

Daran müssen wir uns gewöhnen. Es könnte sonst passieren, dass wir z.B. in einer Schleife alle Elemente durch-laufen möchten und auf das k-te Element zugreifen und einen Fehler verursachen.

i n t [ ] a ;a = new i n t [ 1 0 ] ;f o r ( i n t i =0 ; i <=10; i ++)

System . o u t . p r i n t l n ( "a["+ i +"]="+a [ i ] ) ;

Wenn wir diesen Programmabschnitt aufrufen, erhalten wir folgende Ausgabe mit Fehler:

C : \ Java > j a v a Arraya [ 0 ] = 0a [ 1 ] = 0a [ 2 ] = 0a [ 3 ] = 0a [ 4 ] = 0a [ 5 ] = 0a [ 6 ] = 0a [ 7 ] = 0a [ 8 ] = 0a [ 9 ] = 0E x c e p t i o n i n t h r e a d " main " j a v a . l a n g . Ar ray IndexOutOfBoundsExcep t ion : 10a t Array . main ( Array . j a v a : 5 )

Wir haben in diesem Beispiel gleich mal gesehen, wie ein int-Array erzeugt wird. Um ein k-elementiges Array zuerzeugen, schreiben wir:

<Datentyp>[] <name>;

<name> = new <Datentyp>[k];

oder in einer Zeile:

<Datentyp>[] <name> = new <Datentyp>[k];

Mit dem Befehl new wird Speicher für das Array bereitgestellt. Eine genauere Beschreibung werden wir spätervornehmen.

Das obere Beispiel zeigt auch, wie wir auf die einzelnen Elemente über einen Index zugreifen können. Wir könnendie Inhalte auslesen, oder auch neue hineinschreiben:

i n t [ ] a = { 1 , 2 , 3 , 4 , 5 } ;a [ 2 ] = 4 ;

Sollten wir schon bei der Erzeugung des Arrays wissen, welchen Inhalt die Elemente haben sollen, dann könnenwir das so vornehmen („Literale Erzeugung“ [4]):

i n t [ ] a = { 1 , 2 , 3 , 4 , 5 } ;f o r ( i n t i =0 ; i <5 ; i ++)

System . o u t . p r i n t l n ( "a["+ i +"]="+a [ i ] ) ;

Page 9: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

5.1. ARRAYS UND MATRIZEN 53

5.1.2 Matrizen oder multidimensionale Arrays

Für viele Anwendungen ist es notwendig Arrays mit mehreren Dimensionen anzulegen und zu verwenden. EinSpezialfall mit der Dimension 2 ist die Matrix. Wir haben ein Feld von Elementen der Größe nxm.

Wir erzeugen eine nxm Matrix, indem wir eine Dimension dazu nehmen:

i n t [ ] [ ] a = new i n t [ n ] [m] ;a [ 4 ] [ 1 ] = 2 7 ;

Auf diese Weise können wir sogar noch mehr Dimensionen erzeugen:

i n t [ ] [ ] [ ] [ ] a = new i n t [ k ] [ l ] [m] [ n ] ;

5.1.3 Conway’s Game of Life

Damit wir unsere neu gewonnenen Kenntnisse über Matrizen gleich mal anwenden können, beschäftigen wir unsmit Conway’s Spiel des Lebens1 (bei Wikipedia [19] nachzulesen). Man stelle sich vor, die Welt bestünde nur auseiner 2-dimensionalen Matrix. Jeder Eintrag (wir nennen Sie jetzt mal Zellen) kann zwei Zustände annehmen, istentweder lebendig oder tot. Jede Zelle interagiert mit seinen 8 Nachbarn.

Diese Interaktion unterliegt den folgenden 4 Regeln:

1Mein Großvater brachte mir damals die Programmierung mit diesem Beispiel in BASIC bei. Es hat einen nachhaltigen Eindruck hinterlas-sen und motivierte mich weiter zu machen. Man könnte sagen, dass Conway’s Spiel des Lebens mein Interesse für die Informatik und geradezur KI geweckt hat.

Page 10: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

54 KAPITEL 5. TAG 4: VERWENDUNG EINFACHER DATENSTRUKTUREN

1. jede lebendige Zelle, die weniger als 2 lebendige Nachbarn hat stirbt an Einsamkeit

2. jede lebendige Zelle mit mehr als 3 lebendigen Nachbarn stirbt an Überbevölkerung

3. jede lebendige Zelle mit mit 2 oder 3 Nachbarn fühlt sich wohl und lebt weiter

4. jede tote Zelle mit genau 3 lebendigen Nachbarn wird wieder zum Leben erweckt

Die Idee besteht nun darin eine Weltkonstellation vorzugeben, sei es zufällig oder konkret. Das nennen wir dann dieerste Generation. Die zweite Generation entsteht nun dadurch, dass gleichzeitig für alle Zellen, lebendig oder tot,die vier Regeln untersucht werden und damit entschieden wird, ob die Zelle in der nächsten Generation lebendigoder tot ist. Lässt man ein solches System mit einer zufälligen Konstellation laufen, das heißt, wir schauen uns wiein einem Film die Generationen nacheinander an, dann erinnert uns das Zusammenspiel von Leben und Tot an z.B.Bakterienkulturen in einer Petrischale.

Es gibt viele Variationen und Darstellungsmöglichkeiten. Ich habe hier mal eine Applet-Version aus dem Internet(von der Seite [20]) ausprobiert und man kann schön zwei aufeinander folgende Generationen sehen.

Die zweite Abbildung ist die Nachfolgegeneration der ersten. Man kann sich ein beliebiges Element aus der erstenAbbildung auswählen und prüfen, ob das Zielelement in der zweiten Abbildung den Regeln entsprechend gesetztwurde. Schauen wir uns beispielsweise das Element (von links oben, erst x- dann y-Koordinate) [13,7] an. Esdürfte nach Regel 1, da es nur einen Nachbarn hat, nicht mehr überleben und das tut es auch.

In den Jahren des Experimentierens sind viele interessante Konstellationen aufgetaucht, beispielsweise gibt esMuster, die scheinbar endlos neue Generationen erzeugen, oder andere, die zyklisch bestimmte Zustände anneh-men.

Page 11: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

5.1. ARRAYS UND MATRIZEN 55

5.1.3.1 Einfache Implementierung

Unsere Aufgabe wird es nun sein, eine sehr einfache Version zu implementieren. Wir benötigen dazu eine nxmMatrix welt und setzen die Elemente welt[i, j] auf 0 für tot und 1 für lebendig. Damit hätten wir uns eine einfa-che Umgebung definiert. Nun müssen wir diese Matrix mit Werten füllen. In einem späteren Kapitel werden wirbesprechen, wie es möglich ist Zufallszahlen zu erzeugen, daher müssen wir jetzt die Werte „per Hand“ setzen.

Angenommen wir haben diese Matrix und die jedes Element steht entweder auf 0 oder 1. Um nun eine Folgege-neration zu berechnen, müssen wir eine zweite, leere Matrix weltneu erzeugen. Nun gehen wir systematisch überalle Elemente der welt und prüfen die 8 Nachbarn. Die Regeln liefern eine eindeutige Entscheidung, ob wir in derneuen Matrix an der gleichen Stelle den Wert 0 oder 1 setzen.

Wir könnten systematisch durch die welt laufen, indem wir zwei for-Schleifen verwenden:

1 import j a v a . u t i l . Random ; / / e r l ä u t e r n wi r s p ä t e r2 p u b l i c c l a s s GameOfLife {3 p u b l i c s t a t i c vo id gebeAus ( boolean [ ] [ ] m) {4 / / Ein "X" s i m b o l i s i e r t e i n e l e b e n d i g e Z e l l e5 f o r ( i n t i =0 ; i <10; i ++){6 f o r ( i n t j =0 ; j <10; j ++){7 i f (m[ i ] [ j ] ) System . o u t . p r i n t ( "X " ) ;8 e l s e System . o u t . p r i n t ( " " ) ;9 }

10 System . o u t . p r i n t l n ( ) ;11 }12 }13

14 / / D ie se Methode l ä ß t s i c h s i c h e r l i c h s c h ö n e r s c h r e i b e n − wir15 / / n u t z e n h i e r d i e T a t s a c h e aus , d a s s J ava e i n e n F e h l e r e r z e u g t ,16 / / wenn wi r a u f e i n Element a u ß e r h a l b d e r M a t r i x z u g r e i f e n17 p u b l i c s t a t i c i n t zaehleUmgebung ( boolean [ ] [ ] m, i n t x , i n t y ) {18 i n t r e t = 0 ;19 f o r ( i n t i =( x−1); i <( x +2) ;++ i ) {20 f o r ( i n t j =( y−1); j <( y +2) ;++ j ) {21 t r y {22 i f (m[ i ] [ j ] )23 r e t += 1 ;24 }25 catch ( IndexOutOfBoundsExcep t ion e ) { }26 }27 }28 / / e i n e n z u v i e l m i t g e z a e h l t ?29 i f (m[ x ] [ y ] )30 r e t −= 1 ;31

Page 12: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

56 KAPITEL 5. TAG 4: VERWENDUNG EINFACHER DATENSTRUKTUREN

32 re turn r e t ;33 }34

35 p u b l i c s t a t i c vo id main ( S t r i n g [ ] a r g s ) {36 / / u n s e r e Welt s o l l aus 10 x10 Elemente b e s t e h e n37 boolean [ ] [ ] w e l t = new boolean [ 1 0 ] [ 1 0 ] ;38 boolean [ ] [ ] w e l t _ n e u = new boolean [ 1 0 ] [ 1 0 ] ;39

40 / / ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

41 / / E r z e u g t e i n e z u f ä l l i g e K o n s t e l l a t i o n von E i ns e n und N u l l e n42 / / i n d e r M a t r i x w e l t . Die Chancen l i e g e n b e i 50%, d a s s e i n e43 / / Z e l l e l e b e n d i g i s t .44 Random g e n e r a t o r = new Random ( ) ;45 double z u f a l l s w e r t ;46 f o r ( i n t i =0 ; i <10; i ++){47 f o r ( i n t j =0 ; j <10; j ++){48 z u f a l l s w e r t = g e n e r a t o r . nex tDoub le ( ) ;49 i f ( z u f a l l s w e r t > = 0 . 5 )50 w e l t [ i ] [ j ] = t rue ;51 }52 }53 / / ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

54

55 / / Ausgabe d e r e r s t e n G e n e r a t i o n56 System . o u t . p r i n t l n ( "Generation 1" ) ;57 GameOfLife . gebeAus ( w e l t ) ;58

59 i n t n a c h b a r n ;60 f o r ( i n t i =0 ; i <10; i ++){61 f o r ( i n t j =0 ; j <10; j ++){62 / / Z ae h l e d i e Nachbarn63 n a c h b a r n = zaehleUmgebung ( wel t , i , j ) ;64

65 i f ( w e l t [ i ] [ j ] ) {66 / / Rege l 1 , 2 :67 i f ( ( nachbarn <2) | | ( nachbarn > 3 ) )68 w e l t _ n e u [ i ] [ j ] = f a l s e ;69

70 / / Rege l 3 :71 i f ( ( n a c h b a r n ==2) | | ( n a c h b a r n ==3) )72 w e l t _ n e u [ i ] [ j ] = t rue ;73 }74 e l s e {75 / / Rege l 4 :76 i f ( n a c h b a r n ==3)77 w e l t _ n e u [ i ] [ j ] = t rue ;78 }79 }80 }81 / / Ausgabe d e r z w e i t e n G e n e r a t i o n82 System . o u t . p r i n t l n ( "Generation 2" ) ;83 GameOfLife . gebeAus ( w e l t _ n e u ) ;84 }85 }

Unser Programm GameOfLife.java erzeugt zunächst zwei Matrizen der Größe 10x10. Dann wird die Matrix weltzufällig mit 1 und 0 gefüttert. Mit Zufallsgeneratoren beschäftigen wir uns aber erst später in Abschnitt 8.2.1. Diemit Zufallszahlen gefütterte welt lassen wir uns auf dem Bildschirm ausgeben, wobei ein X für eine lebendige undeine Lücke für eine tote Zelle steht. Im Anschluss daran gehen wir über alle Elemente der welt und wenden die 4Regeln zu Erzeugung einer neuen Generation weltneu an.

Schließlich geben wir die neu berechnete Generation wieder aus und können überprüfen, ob die Regeln eingehaltenwurden.

Page 13: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

5.2. STACK UND WARTESCHLANGE 57

5.2 Stack und Warteschlange

Es gibt zwei weitere sehr elementare Datenstrukturen, deren Recherche ich dem Leser ans Herz legen möchte. EinStack kann als Papierkorb angesehen werden, das Element, welches als letztes in den Papierkorb gelegt wurde,kann als erstes wieder herausgenommen werden usw. Bei einer Warteschlange verhält es sich wie im wahrenLeben. Wir stellen uns irgendwo an und müssen warten, bis alle „Elemente“ vor uns abgearbeitet wurden, erst dannsind wir an der Reihe. Es sei denn, es handelt sich um eine Prioritätswarteschlange, dann könnte beispielsweiseeine ältere Dame den Vorzug erhalten und wir müssen noch ein wenig länger warten.

5.3 Zusammenfassung und Checkliste

Zusammenfassung

Checkliste

4 einfache und mehrdimensionale Arrays

4 Listen, einfach und doppelt verkettet

4 Handhabung der Datenstruktur vector

5.4 Aufgaben

Übung 1) Arbeiten Sie sich in die Themen Stack und Warteschlange in Java ein. Sie können beispielsweisefolgende Literatur [11] studieren. Versuchen Sie nach dieser Anleitung einen Stack und eine Warteschlangemit einem Array zu realisieren (kleiner Hinweis: bei der Wartenschlangenimplementierung sollten Sie einzyklisches Array simulieren). Sie können dabei voraussetzen, dass die Einträge in die Datenstrukturen nurvom Datentyp int sind.

Übung 2) Schreiben eine Methode, die als Eingaben zwei int-Arrays a und b erhält (die Eingabearrays sollen alsSpaltenvektoren interpretiert werden). Die Funktion liefert die Addition beider Vektoren, falls Sie die gleicheDimension besitzen und Null sonst.

Übung 3) Analog zu Übung 2 sollen Funktionen für Vektorsubtraktion und das Produkt aus Vektor und Skalarimplementiert werden.

Übung 4) Schreibe eine Funktion, die die Matrizenmultiplikation ausführt. Falls es Einschränkungen geben sollte,so kommentiere Dein Programm und überprüfe die Daten entsprechend.

Übung 5) Experimentiere mit dem Programm aus der Vorlesung „Conway’s Game of Life“. Erweitere das Pro-gramm so, dass beliebig viele Generationen ausgeführt werden können. Finde Muster, die sich immer repro-duzieren oder Besonderheiten aufweisen. Eine Internetrechersche ist sehr erwünscht.

Übung 6) Schreibe ein Programm, das neben der main-Funktion eine weitere enthält. Erzeuge in der main einezwei identische int-Listen der Länge 10 mit Zahlen. Übergib eine der beiden Listen per Parameterübergabean die Funktion. Die Funktion soll die Reihenfolge der Werte innerhalb dieses Parameters umdrehen, aberkeinen Rückgabewert liefern. Wir hatten besprochen, dass eigentlich nichts besonderes passieren dürfte, daes sich um lokale Variablen handelt. Um das zu überprüfen gib die beiden Listeninhalte in der main nachVerwendung der Funktion aus.Bist Du erstaunt? Den Grund erfährst Du später in Abschnitt 7.2.

Page 14: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

58 KAPITEL 5. TAG 4: VERWENDUNG EINFACHER DATENSTRUKTUREN

Page 15: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

Kapitel 6

Tag 5: Debuggen und Fehlerbehandlungen

Zum Handwerkzeug eines Programmierers gehört die Fähigkeit Fehler in seinen und anderen Programmen aufzu-spüren und zu behandeln. Die beste Methode ist sicherlich die Investition in ein gutes Konzept, um viele Fehlervor der Programmierung auszuschliessen.

6.1 Das richtige Konzept

Es sollte bei der Entwicklung darauf geachtet werden, dass nicht allzu viele Programmzeilen in eine Funktiongehören.

Das Problem sind oft wiederverwendete Variablen oder Seiteneffekte.

Besser ist es, das Programm zu gliedern und in Programmabschnitte zu unterteilen. Zum einen wird damit dieÜbersicht gefördert und zum anderen verspricht die Modularisierung den Vorteil, Fehler in kleineren Program-mabschnitten besser auszuspüren und zu vermeiden.

Zum Weg der Modularisierung gehören auch Einschränkungen (Englisch: constraints). Beim Eintritt in einenProgrammabschnitt (z.B. eine Funktion), müssen die Eingabeparameter überprüft und damit klargestellt werden,dass der Programmteil mit den gewünschten Daten arbeiten kann. Das gleiche gilt für die Ausgabe, der Entwicklerder Funktion ist dafür verantwortlich, dass auch die richtigen Berechnungen durchgeführt und zurückgeliefertwerden.

59

Page 16: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

60 KAPITEL 6. TAG 5: DEBUGGEN UND FEHLERBEHANDLUNGEN

Kommentare sind hier unverzichtbar und fördern die eigene Vorstellung der Funktionsweise eines Programmab-schnitts. Als Beispiel schauen wir uns mal die Fakultätsfunktion an:

1 p u b l i c c l a s s F a k u l t a e t {2 /∗3 F a k u l t ä t s f u n k t i o n l i e f e r t f ü r i =1 . . 13 d i e e n t s p r e c h e n d e n4 F u n k t i o n s w e r t e i ! = i ∗ ( i −1)∗( i − 2 ) ∗ . . . ∗ 15

6 Der Rückgabewer t l i e g t im B e r e i c h 1 . . 4790016007

8 S o l l t e e i n e f a l s c h e Eingabe v o r l i e g e n , so l i e f e r t das Programm9 a l s E r g e b n i s −1.

10 ∗ /11 p u b l i c s t a t i c i n t f a k u l t a e t ( i n t i ) {12 / / I s t d e r Wert a u s s e r h a l b des e r l a u b t e n B e r e i c h s ?13 i f ( ( i < = 0 ) | | ( i >=13) )14 re turn −1;15

16 / / R e k u r s i v e Berechnung d e r F a k u l t a e t17 i f ( i ==1)18 re turn 1 ;19 e l s e20 re turn i ∗ f a k u l t a e t ( i −1);21 }22

23 p u b l i c s t a t i c vo id main ( S t r i n g [ ] a r g s ) {24 f o r ( i n t i =0 ; i <15; i ++)25 System . o u t . p r i n t l n ( "Fakultaet von "+ i +" liefert "+ f a k u l t a e t ( i ) ) ;26 }27 }

Damit haben wir ersteinmal die Ein- und Ausgaben überprüft und sichergestellt, dass wir mit den gewünschtenDaten arbeiten, nun müssen wir dafür Sorge tragen, die Module fehlerfrei zu halten.

Leider treten auch nach den besten Vorbereitungen Fehler in verschiedenen Formen auf. Dabei unterscheidenwir zwischen Fehlern, die das Programm zum Absturz bringen und fehlerhaften Berechnungen. Schauen wir unszunächst an, wie wir Fehler in Java vermeiden können, die das Programm zum Absturz bringen.

6.2 Exceptions in Java

Wenn ein Fehler während der Ausführung eines Programms auftritt, wird ein Objekt einer Fehlerklasse (Exception)erzeugt. Da der Begriff Objekt erst später erläutert wird, stellen wir uns einfach vor, dass ein Programm gestartetwird, welches den Fehler analysiert und wenn der Fehler identifizierbar ist, können wir dieses Programm nach demFehler fragen und erhalten einen Hinweis, der Aufschluss über die Fehlerquelle gibt.

Schauen wir uns ein Beispiel an:

Page 17: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

6.2. EXCEPTIONS IN JAVA 61

1 p u b l i c c l a s s E x c e p t i o n T e s t {2 p u b l i c s t a t i c vo id main ( S t r i n g [ ] a r g s ) {3 i n t d = I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ;4 i n t k = 1 0 / d ;5 System . o u t . p r i n t l n ( "Ergebnis ist "+k ) ;6 }7 }

Auf den ersten Blick ist kein Fehler erkennbar, aber ein Test zeigt schon die Fehleranfälligkeit des Programms.

C: \ > j a v a E x c e p t i o n T e s t 2E r g e b n i s i s t 5

C: \ > j a v a E x c e p t i o n T e s t 0E x c e p t i o n i n t h r e a d " main " j a v a . l a n g . A r i t h m e t i c E x c e p t i o n : / by z e r o

a t E x c e p t i o n T e s t . main ( E x c e p t i o n T e s t . j a v a : 5 )

C: \ > j a v a E x c e p t i o n T e s t dE x c e p t i o n i n t h r e a d " main " j a v a . l a n g . NumberFormatExcept ion : For i n p u t s t r i n g : " d"

a t j a v a . l a n g . NumberFormatExcept ion . f o r I n p u t S t r i n g ( Unknown Source )a t j a v a . l a n g . I n t e g e r . p a r s e I n t ( Unknown Source )a t j a v a . l a n g . I n t e g e r . p a r s e I n t ( Unknown Source )a t E x c e p t i o n T e s t . main ( E x c e p t i o n T e s t . j a v a : 4 )

Zwei Fehlerquellen sind hier erkennbar, die Eingabe eines falschen Typs und die Eingabe einer 0, die bei derDivision einen Fehler verursacht. Beides sind für Java wohlbekannte Fehler, daher gibt es auch in beiden Fällenentsprechende Fehlerbezeichnungen NumberFormatException und ArithmeticException.

Um nun Fehler dieser Art zu vermeiden, müssen wir zunächst auf die Fehlersuche gehen und den Abschnitt identi-fizieren, der den Fehler verursacht. Wir müssen uns dazu die Frage stellen: In welchen Situationen (unter welchenBedingungen) stürzt das Programm ab? Damit können wir den Fehler einengen und den Abschnitt besser lokali-sieren. Dann müssen wir Abhängigkeiten überprüfen, welche Module sind für die Eingabe zuständig?

Angenommen, wir haben einen Bereich lokalisiert und wollen diesen nun beobachten, dazu verwenden wir dietry-catch-Klausel.

6.2.1 Einfache Try-Catch-Behandlung

Die Snytax dieser Klausel sieht wie folgt aus:

try {

<Anweisung>;

...

<Anweisung>;

} catch(Exception e){

<Anweisung>;

}

Um unser Programm aus Abschnitt 6.2 vor einem Absturz zu bewahren, wenden wir diese Klausel an und testendas Programm.

1 p u b l i c c l a s s E x c e p t i o n T e s t 2 {2 p u b l i c s t a t i c vo id main ( S t r i n g [ ] a r g s ) {3 t r y {4 i n t d = I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ;

Page 18: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

62 KAPITEL 6. TAG 5: DEBUGGEN UND FEHLERBEHANDLUNGEN

5 i n t k = 1 0 / d ;6 System . o u t . p r i n t l n ( "Ergebnis ist "+k ) ;7 } catch ( E x c e p t i o n e ) {8 System . o u t . p r i n t l n ( "Fehler ist aufgetreten..." ) ;9 }

10 }11 }

Wie testen nun die gleichen Eingaben.

C: \ > j a v a E x c e p t i o n T e s t 2E r g e b n i s i s t 5

C: \ > j a v a E x c e p t i o n T e s t 0F e h l e r i s t a u f g e t r e t e n . . .

C: \ > j a v a E x c e p t i o n T e s t dF e h l e r i s t a u f g e t r e t e n . . .

Einen Teilerfolg haben wir nun schon zu verbuchen, da das Programm nicht mehr abstürzt. Der Bereich in dengeschweiften Klammern nach dem Schlüsselwort try wird gesondert beobachtet. Sollte ein Fehler auftreten, sowird die weitere Abarbeitung innerhalb dieser Klammern abgebrochen und der Block nach dem Schlüsselwortcatch ausgeführt.

6.2.2 Mehrfache Try-Catch-Behandlung

Dummerweise können wir nun die Fehler nicht mehr eindeutig identifizieren, da sie die gleiche Fehlermeldungproduzieren. Um die Fehler aber nun eindeutig abzufangen, lassen sich einfach mehrere catch-Blöcke mit ver-schiedenen Fehlertypen angeben:

try {

<Anweisung>;

...

<Anweisung>;

} catch(Exceptiontyp1 e1){

<Anweisung>;

} catch(Exceptiontyp2 e2){

<Anweisung>;

} catch(Exceptiontyp3 e3){

<Anweisung>;

}

Wenden wir die neue Erkenntnis auf unser Programm an:

1 p u b l i c c l a s s E x c e p t i o n T e s t 3 {2 p u b l i c s t a t i c vo id main ( S t r i n g [ ] a r g s ) {3 t r y {4 i n t d = I n t e g e r . p a r s e I n t ( a r g s [ 0 ] ) ;5 i n t k = 1 0 / d ;6 System . o u t . p r i n t l n ( "Ergebnis ist "+k ) ;7 } ca tch ( NumberFormatExcept ion n f e ) {8 System . o u t . p r i n t l n ( "Falscher Typ! Gib eine Zahl ein ..." ) ;9 } ca tch ( A r i t h m e t i c E x c e p t i o n ae ) {

10 System . o u t . p r i n t l n ( "Division durch 0! ..." ) ;11 } ca tch ( E x c e p t i o n e ) {12 System . o u t . p r i n t l n ( "Unbekannter Fehler aufgetreten ..." ) ;13 }14 }15 }

Page 19: Tag 3: Daten laden und speichern - UserPages < Tecpage.mi.fu-berlin.de/block/JavaBlockKurs/Vorlesung3/Skript_Teil_3.pdf · 46 KAPITEL 4. TAG 3: DATEN LADEN UND SPEICHERN 1 // MirIstWarm

6.3. ZUSAMMENFASSUNG UND CHECKLISTE 63

Bei den schon bekannten Eingaben liefert das Programm nun folgende Ausgaben:

C: \ > j a v a E x c e p t i o n T e s t 3 2E r g e b n i s i s t 5

C: \ > j a v a E x c e p t i o n T e s t 3 0D i v i s i o n durch 0 ! . . .

C: \ > j a v a E x c e p t i o n T e s t 3 dF a l s c h e r Typ ! Gib e i n e Zahl e i n . . .

Hier sei nur am Rande erwähnt, dass die try-catch-Klausel noch weitere Eigenschaften besitzt und Fehlerklassenselber programmiert werden können. Da wir aber noch kein Verständnis für Objektorientierung entwickelt habenund das erst im Folgekapitel besprochen wird, lege ich dem interessierten Leser hier ans Herz sich zunächst mitdem erweiterten Klassenkonzept auseinander zu sezten und später dieses Konzept nachzuarbeiten (z.B. hier [1, 5]).

6.3 Zusammenfassung und Checkliste

Zusammenfassung

Checkliste

4 Konzept und Modularisierung

4 Exceptions mit try-catch-Klausel aufspüren

4 Zeilenweises Debuggen

6.4 Aufgaben

Übung 1) In Aufgabensammlung 2 Aufgabe 3 (ii) sollte die Summe berechnet werden. Leider liefert der folgendeProgrammcode nicht die gewünschten Ergebnisse:public static double sum1()

{

int i, startwert=1;

double d, h;

for (i=--startwert; i>100; i++)

System.out.println(d);

{h = (i*i+i)/2;

d = d+h;

}

return d;

}

Finde die Fehler und argumentiere, was da nicht stimmt.