Objektorientierte Programmierung Java-Tutorium, Sprachliche Informationsverarbeitung, Wintersemester 2006/2007, Fabian Steeg 01. Sitzung, 19.10.2006: Eclipse, Klassen, Attribute und Methoden 02. Sitzung, 26.10.2006: Klassen, Instanzen, Attribute, lokale Variablen, Wertzuweisung 03. Sitzung, 02.11.2006: Parameterübergabe, Plus-Operator 04. Sitzung, 09.11.2006: Konstruktoren und Rückgabewerte 05. Sitzung, 16.11.2006: Methoden, Rückgabewerte, Literale, Kontrollstrukturen 06. Sitzung, 23.11.2006: Endlosschleifen, Debugger, Datentypen 07. Sitzung, 30.11.2006: Zeichenkettenverarbeitung, Vector und Vererbung 08. Sitzung, 07.12.2006: Vector, Vererbung, Casting und Typsicherheit (durch Generics) 09. Sitzung, 14.12.2006: Sternchen-Karos (Übung zu Schleifen) 10. Sitzung, 11.01.2007: Arrays 11. Sitzung, 18.01.2007: Vector statt Matrix 12. Sitzung, 25.01.2007: Interfaces und Exceptions 13. Sitzung, 01.02.2007: Streams, Reader, Writer, Scanner (IO) 14. Sitzung, 08.02.2007: Sternchen-Karos II (Übung zu IO) 01. Sitzung, 19.10.2006: Eclipse, Klassen, Attribute und Methoden /* Eine Klasse mit einem Attribut (matrikelnummer) und einer Methode (immatrikulieren) */ class Student { Integer matrikelnummer; void immatrikulieren(){ System.out.println("Student immatrikuliert!"); } } 02. Sitzung, 26.10.2006: Klassen, Instanzen, Attribute, lokale Variablen, Wertzuweisung // Einsteigpunkt des Programms: eine Klasse mit einer main-Methode class Programm { // Die main-Methode, wird von der JVM aufgerufen public static void main(String[] args) { // Eine Instanz erstellen: Student hans = new Student(); // Eine Methode aufrufen: hans.immatrikulieren(); // Einem Attribut des Objekts einen Wert zuweisen: hans.matrikelnummer = 3598900; // Den Wert des Attributs einer lokalen Variable zuweisen: Integer hansNummer = hans.matrikelnummer; // Ein Attribut einfach 'auszufuehren' geht nicht: // hans.matrikelnummer; /* (Eine Instanz einer Klasse ist eine Variable und eine Referenz auf ein Objekt.) */ // Eine weitere Instanz erstellen: Student maria = new Student(); // Methodenaufruf: maria.immatrikulieren(); // Wertzuweisung auf Attribut: maria.matrikelnummer = 3598901; // Wertzuweisung auf lokale Variable: Integer mariasNummer = maria.matrikelnummer; // Und am Ende vom Studium hans exmatrikulieren: hans.exmatrikulieren(); // Maria exmatrikulieren: maria.exmatrikulieren(); } } 03. Sitzung, 02.11.2006: Parameterübergabe, Plus-Operator // Parameteruebergabe class Student { public static void main(String[] args) { Student s1 = new Student(); s1.immatrikulieren(12345, "Hans"); Student s2 = new Student(); s2.immatrikulieren(54321, "Anna"); } void immatrikulieren(Integer matrikelnummer, String name) { System.out.println("Student " + name + " hat die Nummer " } } + matrikelnummer); 04. Sitzung, 09.11.2006: Konstruktoren und Rückgabewerte public class Main { public static void main(String[] args) { Student s1 = new Student(12356, "Hans", 2001); s1.immatrikulieren(); Integer studiendauer1 = s1.studiendauer(2006); System.out.println(studiendauer1); Student s2 = new Student(54321, "Anna", 2003); s2.immatrikulieren(); Integer studiendauer2 = s2.studiendauer(2006); System.out.println(studiendauer2); String thema1 = "Java"; String thema2 = "C++"; Hausarbeit hausarbeit1 = new Hausarbeit(s1, thema1); Hausarbeit hausarbeit2 = new Hausarbeit(s2, thema2); } } class Student { Integer matrikelnummer; String name; Integer anfangsJahr; Student(Integer matrikelnummer, String name, Integer anfangsJahr) { this.matrikelnummer = matrikelnummer; this.name = name; this.anfangsJahr = anfangsJahr; } void immatrikulieren() { System.out.println("Student " + name + " hat die Nummer " } + matrikelnummer); Integer studiendauer(Integer aktuellesJahr) { Integer studiendauer = aktuellesJahr - anfangsJahr; return studiendauer; } } public class Hausarbeit { Student student; String thema; Hausarbeit(Student student, String thema) { this.student = student; this.thema = thema; System.out.println(student.name + " schreibt eine Hausarbeit zum Thema " + thema); } } 05. Sitzung, 16.11.2006: Methoden, Rückgabewerte, Literale, Kontrollstrukturen Eine Methode mit if-else und while-Schleife, eine etwas andere Lösung der Aufgabe aus der Sitzung (Hochzählen, Attribute, Ergebnis: Boolean). Boolean schreiben(Boolean guterTag) { while (geschriebeneSeiten < geforderteSeiten) { if (guterTag) { // Ausgaben, auch zum Testen System.out.println("Heute ist ein guter Tag, " + student.name + " schreibt 5 Seiten zum Thema " + thema); geschriebeneSeiten = geschriebeneSeiten + 5; } else { // Was ist hier unschoen? Wie loest man das? System.out.println("Heute ist kein guter Tag, " + student.name + " schreibt 1 Seite zum Thema " + thema); geschriebeneSeiten = geschriebeneSeiten + 1; } } } // Fallunterscheidung fuers Ergebnis if (geschriebeneSeiten >= geforderteSeiten) { return true; } // Ist dieses else noetig? else { return false; } // Numerale, ganzzahlig: Integer i = 12; // 32 bit (4 byte) Long l = 12L; // 64 bit (8 byte) // Numerale, Dezimalzahlen: Float f = 12.5F; // 32 bit (4 byte) Double d = 12.5; // 64 bit (8 byte) // Literale, alphanumerisch: Character c = '7'; // ein Zeichen String s = "Hallo 1 2 3"; // Zeichenkette // Wahrheitswert-Literal Boolean b = true; // true oder false 06. Sitzung, 23.11.2006: Endlosschleifen, Debugger, Datentypen Ein Programm , das aus Eingaben mehrfach hintereinander vorkommende Zeichen zu einem zusammenfasst und so etwa aus "aaabbcccdd" "abcd" macht. Unsere Klasse, soweit wir gekommen waren: public class Compressor { /* * Unser Ziel: Mehrfach hintereinander auftretende Buchstaben zu einem * kuerzen, wie im folgenden Beispiel: */ public static void main(String[] args) { String compressed = new Compressor().compress("aaabbbcccddd"); if (compressed.equals("abcd")) { System.out.println("Funktioniert"); } else { System.out.println("Funktioniert nicht: " + compressed); } } /* * Sowas wie das oben hat schonmal jemand gebraucht und gemacht: JUnit (Run * As -> JUnit Test, statt Run As -> Java Application. Damit werden die * tests statt der main ausgefuehrt.) Wenn was rot ist (ev. wiederholt) * Rechtsklick auf die Gluehbirne links -> Quick Fix, erstes Angebot * auswaehlen). */ @Test /* } public void testCompressor() { assertEquals("abcd", compress("aaabbbcccddd")); } * Idee: Den String durchgehen und immer wenn das naechste Zeichen ein * anderes ist als das aktuelle Zeichen, das aktuelle Zeichen ergaenzen. */ private String compress(String input) { Integer length = input.length(); String result = ""; for (Integer pos = 0; pos < length - 1; pos++) { Character current = input.charAt(pos); if (current != input.charAt(pos + 1)) { result = result + current; } } return result; } /* * Aktuelles Problem: Was ist mit den Zeichen am Ende? Ausserdem, wie sieht * es etwa mit solchen Eingaben aus: "abbccdd", "abbccd", "aabcdd" oder auch * "a"? Wenn man die jeweils als eigene Methode mit @Test testet, testet * man ruck-zuck ein grosse Zahl von verschiedenen Beispielen mit einem * Knopfdruck, und kann auf einen Blick sehen welche klappen und welche * nicht. */ Diagramm zur Veranschaulichung des doppelten Datentypen-Systems für grundlegende Typen: Übersicht grundlegender Kontrollstrukturen: 07. Sitzung, 30.11.2006: Zeichenkettenverarbeitung, Vector und Vererbung UML Klassendiagramm unserer Filter: Unser allgemeiner Filter, der alles durchlässt: import java.util.Arrays; import java.util.Vector; public class Filter { Vector text; Filter(Vector text) { this.text = text; } Vector filter() { Vector result = new Vector(); Integer length = text.size(); for(Integer i = 0;i if(accept(current)){ result.add(current); } } return result; } Boolean accept(String word) { return true; } String current = (String) text.get(i); public static void main(String[] args) { Filter filter = new Filter( new Vector(Arrays.asList("Aloha", "Kaluha", "Heinz", "Herbert"))); Vector res = filter.filter(); System.out.println("Herausgefiltert: "); for (Integer i = 0; i < res.size(); i++) { System.out.println(res.get(i)); } } } Unser spezieller Filter, der aller Woerter herausfiltert, die hawaiiansche Wörter sein könnten, soweit wir waren. Es fehlt noch eine Implementierung der Methode hawaiianischerBuchstabe(Character buchstabe). Zur Erinnerung: Das Hawaiianische verwendet die bekannten Vokale (a, e, i, o, u) sowie die Konsonanten k, l, m, n, p, w, h und das Zeichen ' (Hochkomma), um es ganz komplett zu machen. import java.util.Arrays; import java.util.Vector; public class HawaiianFilter extends Filter{ HawaiianFilter(Vector text){ super(text); } Boolean accept(String word){ for(Integer pos = 0;pos return false; } } return true; } if(!hawaiianischerBuchstabe(word.charAt(pos))){ public static void main(String[] args) { Filter filter = new HawaiianFilter( new Vector(Arrays.asList("Aloha", "Kaluha", "Heinz", "Herbert"))); Vector res = filter.filter(); System.out.println("Herausgefiltert: "); for (Integer i = 0; i < res.size(); i++) { System.out.println(res.get(i)); } } } Eine Lösung zu unserer Aufgabe von letzter Woche, wie wir sie heute zusammen geschrieben haben: /* * Idee: Den String durchgehen und immer wenn der aktuelle Buchstabe nicht * der gleiche ist wie der, den wir zuletzt angehangen haben (oder wir noch * gar nichts angehangen haben haben), haengen wir den aktuellen dran. */ private String compress(String input) { Integer length = input.length(); String result = ""; for (Integer pos = 0; pos < length; pos++) { Character current = input.charAt(pos); if (result.length() == 0 || current != result.charAt(result.length() - 1)) { result = result + current; } } return result; } 08. Sitzung, 07.12.2006: Vector, Vererbung, Casting und Typsicherheit (durch Generics) UML Klassendiagramm unserer Filter: Der allgemeinste Filter (hier mit eigenem Tokenizer, der einen String an dem angegebenen Zeichen trennt und jedes Wort in einen Vector legt, ist nicht allzu schwierig zu implementieren. Wer keine Lust hat sowas zu schreiben kann auch die bisher noch etwas kryptische Zeile darunter verwenden, um das mit Java-Bordmitteln zu machen): public class Filter { Vector<String> input; Filter(Vector<String> input) { this.input = input; } Filter(String input) { this.input = new Tokenizer(input).tokenize(' '); // this.input = new Vector<String>(Arrays.asList(input.split(" "))); } } Die filter-Methode von WordFilter, der Superklasse für Filter, die Wörter herausfiltern: Vector filter() { Vector<String> result = new Vector<String>(); for (int i = 0; i < input.size(); i++) { if (acceptable(input.get(i))) { result.add(input.get(i)); } } return result; } Die filter-Methode von CharFilter, der Superklasse fuer Filter, die Zeichen herausfiltern: Vector filter() { Vector<Character> result = new Vector<Character>(); for (int i = 0; i < input.size(); i++) { String string = input.get(i); for (int j = 0; j < string.length(); j++) { char character = string.charAt(j); if (acceptable(character)) { result.add(character); } } } return result; } Die acceptable-Methode, z.B. für hawaiianische Wörter: boolean acceptable(String string) { for (int i = 0; i < string.length(); i++) { if (!("aeiouhklmnpw".contains(string.charAt(i)+""))) { return false; } } return true; } Die acceptable-Methode, z.B. für Vokale: boolean acceptable(Character c){ return "aeiouAEIOU".contains(c+""); } Testen kann man das ganze dann z.B. für Palindrome so: @Test public void testPalindromFilter() { WordFilter filter = new PalindromeFilter("anna rehe ehe netten"); assertEquals(new Vector<String>(Arrays.asList("anna", "ehe", "netten")), filter.filter()); } Oder für Vokale so: @Test public void testVowelFilter() { CharFilter filter = new VowelFilter("anna rehe ehe netten"); assertEquals(new Vector<Character>(Arrays.asList('a', 'a', 'e', 'e', 'e', 'e', 'e', 'e')), filter.filter()); } 09. Sitzung, 14.12.2006: Sternchen-Karos (Übung zu Schleifen) Ausgabe: * *** ***** ******* ********* ******* ***** *** * * * * * * * * * * * * * * * * * * * * * * * * * * Eine Loesung, optional mit eingefuegten Leerzeichen, unter Angabe der Hoehe der zugrunde liegenden Pyramide, was ja vielleicht nuetzlich sein koennte… public class Diamond { public static void main(String[] args) { new Diamond(5, false).print(); new Diamond(5, true).print(); } private int rows; private int max; private boolean blanks; int steps = 2; public Diamond(int rows, boolean blanks) { this.rows = rows; this.blanks = blanks; // Die breiteste Stelle der Pyramide: das erste Sternchen // plus fuer jede weitere Stufe die Anzahl zusaetzlicher // Sternchen dazu (erhoeht man steps wirds ein Quadrat) } this.max = 1 + (rows - 1) * steps; private void print() { for (int row = 1, stars = 1; row <= rows; row++, stars += steps) { line(stars); } for (int row = rows-1, stars = max-steps; row > 0; row--, stars -= steps) { line(stars); } } private void line(int stars) { int blanks = max - stars; print(blanks / 2, ' '); print(stars, '*'); print(blanks / 2, ' '); System.out.println(); } private void print(int i, char c) { for (int j = 1; j <= i; j++) { if (blanks && j % 2 == 0) { System.out.print(' '); } else } } System.out.print(c); } 10. Sitzung, 11.01.2007: Arrays //fuer matrizen in denen alle elemente gleich lang sind public class SimpleFlip { @Test public void flipping() { Character[][] in = { { 'h', 'a', 'l', 'l', 'o' }, { 'w', 'e', 'l', 't', '!' } }; Character[][] out = { { 'h', 'w' }, { 'a', 'e' }, { 'l', 'l' }, { 'l', 't' }, { 'o', '!' } }; assertEquals(flip(in), out); } private Character[][] flip(Character[][] in) { Character[][] res = new Character[in[0].length][in.length]; // es geht auch andersrum als wir es heute gemacht haben: for (int i = 0; i < res.length; i++) { for (int j = 0; j < res[0].length; j++) { res[i][j] = in[j][i]; } } return res; } } 11. Sitzung, 18.01.2007: Vector statt Matrix // fuer matrizen mit unterschiedlich langen elementen public class Flip { @Test public void flipping() { Character[][] in = { { 'h', 'a', 'l', 'l', 'o' }, { 'w', 'e', 'l', 't' } }; } Character[][] out = { { 'h', 'w' }, { 'a', 'e' }, { 'l', 'l' }, { 'l', 't' }, { 'o' } }; assertEquals(flip(in), out); private Character[][] flip(Character[][] in) { // ergebnis in einer flexiblen datenstruktur erzeugen: Vector<Character>> temp = new Vector<Character>>(); for (int i = 0; i < in.length; i++) { for (int j = 0; j < in[i].length; j++) { if (temp.size() < j + 1) temp.add(new Vector<Character>()); Vector<Character> vector = temp.get(j); vector.add(in[i][j]); temp.set(j, vector); } } // ergebnis in die matrix uebertragen: Character[][] res = new Character[temp.size()][]; for (int i = 0; i < res.length; i++) { res[i] = new Character[temp.get(i).size()]; for (int j = 0; j < res[i].length; j++) { res[i][j] = temp.get(i).get(j); } } return res; } } 12. Sitzung, 25.01.2007: Interfaces und Exceptions Eine Bibliothek, in der man verschiedene Medien kaufen oder ausleihen kann (wobei Zeitschriften nur vor Ort, CDs nur gekauft und Buecher gekauft und geliehen werden koennen), koennte man etwa so modellieren: Implementiert etwa so: // TutoriumExceptions.java import java.util.List; import java.util.Vector; /* * Medien sind ein abstraktes Konzept und werden dementsprechend hier als * abstrakte Klasse modelliert. */ abstract class Medium { public String titel; public Medium(String titel) { this.titel = titel; } /* * hier kaemen methoden die was machen, etwa inventarisieren(). Sonst wuerde * man statt einer abstrakten klasse auch hierfuer ein interface verwenden. */ } /* * Unsere konkreten Medien: Buch, CD, Zeitschrift. Buecher koennen geliehen * sowie gekauft werden. CD gibt es nur zu kaufen und Zeitschriften koennen nur * vor Ort gelesen werden. */ class Buch extends Medium implements Leihbar, Kaeuflich { private boolean ausgeliehen; private boolean aufLager; public Buch(String titel) { super(titel); } public boolean ausgeliehen() { return ausgeliehen; } public boolean aufLager() { return aufLager; } } class CD extends Medium implements Kaeuflich { private boolean aufLager; public CD(String titel) { super(titel); } public boolean aufLager() { return aufLager; } } class Zeitschrift extends Medium { public Zeitschrift(String titel) { super(titel); } } /* Interfaces */ interface Kaeuflich { boolean aufLager(); } interface Leihbar { boolean ausgeliehen(); } Eine Abbildung zur Entscheidung, was fuer eine Exception man bei Problemen werfen sollte: Und konkret: /* * Beim Ausleihen von Medien in einer Bibliothek kann vieles schiefgehen. * Probleme werden in Java (wie in anderen OO-Programmiersprachen) mit Exceptions * behandelt. Diese werden geworfen (wo ein Fehler entdeckt wird) und gefangen * (wo der Fehler behandelt wird). */ class Bibliothek { /* * Hier einmal die Verwendung eines interface von Java: List ist ein * interface, das von verschiedenen Klassen implementiert wird, etwa Vector * und ArrayList. Wir verwenden Vector. Wenn aber Vector zu langsam sein * sollte, koennen wir eine ArrayList verwenden, und braeuchten sonst nichts * im code zu aendern, da immer die Methoden in List verwendet werden, nie * solche, die nur in Vector oder ArrayList vorhanden sind. */ List medien = new Vector(); void ausleihen(Medium medium) throws NichtLeihbarException { if (medium instanceof Leihbar && !((Leihbar) medium).ausgeliehen()) { System.out.println("Ausleihe: " + medium.titel); } else { /* * Der seltenste Fall: eine eigene, kontrollierte (checked) * exception (weil der Benutzer das Problem beheben kann, sonst * nehme man eine unkontrollierte, s.u.) mit zusaetzlichen, * komplexen Daten, hier das Medium (sonst sollte man eine * vorhandene checked exception nehmen, z.B.: * * new Exception(medium.title + " ist nicht leihbar!")); * * Zu beachten * ist, dass in einem echten Programm solch ein Fall wie hier } } * normalerweise nicht vorkommen sollte, sondern eben nur * ausnahmsweise (daher exception). Hier heisst das z.B. das * normalerweise alles, was man dieser Methode hier uebergibt * ausleihbar sein sollte. Als Kontrollstruktur sollten exceptions * aus Performanz- und Lesbarkeitsgruenden nicht verwendet werden. */ throw new NichtLeihbarException(medium); void kaufen(Medium medium) { if (medium instanceof Kaeuflich && !((Kaeuflich) medium).aufLager()) { System.out.println("Kauf: " + medium.titel); } else { /* * Der viel haeufigere, normalere Fall: hier werfen wir eine * unkontrollierte exception, denn wenn es nicht kaeuflich ist, kann * man auch nichts mehr machen, also brauche wir auch keine * Behandlung zu erzwingen. Da wir nichts besonderes hinzufuegen * wollen, nehmen wir eine vorhandene unchecked exception, die hier * passt: IllegalArgumentException */ throw new IllegalArgumentException(medium.titel + " konnte nicht gekauft werden!"); } } } /* * Unsere eigene (weil komplexe Information enthaltende), checked (weil man * vernuenftig darauf reagieren kann) exception. */ class NichtLeihbarException extends Exception { Medium medium; public NichtLeihbarException(Medium medium) { this.medium = medium; } } public class TutoriumExceptions { public static void main(String[] args) { Bibliothek bibl = new Bibliothek(); /* * Wir versuchen, eine CD auszuleihen (allerdings kann man CDs nicht * leihen, sondern nur kaufen). D.h. wir haben einen moeglichen Fehler, * der aber zu beheben ist, indem man naemlich im Falle des Fehlers die * CD kauft. */ CD cd = new CD("Niafunke"); try { bibl.ausleihen(cd); } catch (NichtLeihbarException e) { printInfo(e); /* * Auch hier kann etwas schiefgehen, aber da man dann eh nichts mehr * machen kann, verwenden wir dort eine unchecked exception, und * muessen daher hier kein try-catch-finally veranstalten: */ bibl.kaufen(cd); } /* Ein Buch kann ausgeleihen oder auch gekauft werden: */ Buch buch = new Buch("Faust"); try { bibl.ausleihen(buch); } catch (NichtLeihbarException e) { printInfo(e); bibl.kaufen(buch); } /* * Zeitschriften koennen nur vor Ort gelesen werden, man kann sie weder * kaufen noch ausleihen: */ Zeitschrift zeitschrift = new Zeitschrift("Die Zeit"); try { bibl.ausleihen(zeitschrift); } catch (NichtLeihbarException e) { printInfo(e); bibl.kaufen(zeitschrift); } } static void printInfo(NichtLeihbarException e) { System.out.println(e.medium.titel + " konnte nicht ausgeliehen werden, versuche, zu kaufen..."); } } 13. Sitzung, 01.02.2007: Streams, Reader, Writer, Scanner (IO) Unterschiedliche Quellen und Ziele des IO, z.B. Lesen aus Dateien oder von der Tastatur Maschinenlesbares IO (binäre Daten): Streams, z.B. ObjectInputStream und ObjectOutputStream Menschenlesbares IO (plain Text): Reader und Writer, z.B. FileReader und FileWriter Performanzsteigerung durch Pufferung, z.B. BufferedReader und BufferedWriter Komfortables Einlesen, Quelle kann InputStream, Reader, String oder File sein: Scanner Weitere Erklärungen in den Kommentaren nachfolgender Beispiele (als JUnit Tests, s.u.): @Test public void byteStream() throws IOException { int r; // System.in ist ein InputStream, ein Byte-Stream der eigentlich nur // fuer binaere Eingabe taugt, weshalb z.B. Umlaute auf diese Weise // kaputt gehen: while ((r = System.in.read()) != -1) { System.out.println((char) r); } } @Test public void reader() throws IOException { int r; // Um menschenlesbar einzulesen wird der InputStream in einen Reader // gepackt: Reader inputStreamReader = new InputStreamReader(System.in); while ((r = inputStreamReader.read()) != -1) { System.out.println((char) r); } } @Test public void scanner() { // Die Klasse Scanner bietet seit Java 5 eine komfortable Variante, // etwas aus Readern, InputStreams, Strings oder Files einzulesen: Scanner scanner = new Scanner(System.in); String line; while ((line = scanner.nextLine()) != null) { System.out.println(line); } // im Scanner gibts weitere nuetzliche Sachen, etwa Zahlen auslesen: Integer number = scanner.nextInt(); // oder um zu pruefen, was drin ist: Boolean hasDouble = scanner.hasNextDouble(); // und bietet auch Unterstuetzung fuer regulaere Ausdruecke: Boolean hasLetters = scanner.hasNext("[a-zA-Z]+"); } @Test public void encoding() throws FileNotFoundException { // Einem Scanner kann man (wie auch Readern) das Encoding einer Datei // angeben, das beim Einlesen verwendet werden soll: Scanner scanner = new Scanner(new File("temp.txt"), "utf-8"); // Benutzung wie oben… } @Test public void lineReader() throws IOException { // Wenn wir zeilenweise einlesen, verwenden wir einen } // BufferedReader, der mit jedem Reader-Objekt erzeugt werden kann und // mit allen Zeilenumbruch-Markierungen (traditionell: Unix: \\n, // Mac: \\r, Win: \\r\\n): BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(System.in)); String line; while ((line = bufferedReader.readLine()) != null) { System.out.println(line); } @Test public void objects() throws FileNotFoundException, IOException, ClassNotFoundException { // Wir haben ein Object, das Serializable implementiert, z.B. eine // Liste (sowas ist zwar praktisch bringt aber einige Probleme mit // sich; Daten sollten lieber als plain Text und damit menschelesbar // gespeichert werden, praktisch aber ist es z.B. zur voruebergehenden, // internen Speicherung): List<String> words = new ArrayList<String>(Arrays.asList("Halli", "Hallöchen")); // Wir serialisieren das Objekt als eine Datei, mithilfe eines // ObjectOutputStreams und eines FileOutputStreams: String location = "temp.bin"; ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream( location)); out.writeObject(words); // Wir lesen das Object von der Datei ein (mit den entsprechenden // Input-Varianten der Klassen oben): ObjectInputStream in = new ObjectInputStream(new FileInputStream( location)); List<String> deserializedWords = (List<String>) in.readObject(); // Und schauen mal, was drin ist: for (String word : deserializedWords) { System.out.println(word); } } 14. Sitzung, 08.02.2007: Sternchen-Karos II (Übung zu IO) Eine Erweiterung unserer Sternchen-Karos um eine Möglichkeit, das Ergebnis zu speichern und einzulesen. public class IO { public static void main(String[] args) throws FileNotFoundException { System.out.println("(N)eu erstellen oder Datei (Ö)ffnen"); Scanner scanner = new Scanner(System.in); String zeile = scanner.nextLine(); File file = new File("temp.txt"); if (zeile.equalsIgnoreCase("N")) { System.out.println("Größe angeben: "); int x = scanner.nextInt(); System.out.println("Gewählte Größe: " + x); try { FileWriter writer = new FileWriter(file); /* * statt dem FileWriter koennte man hier zb einen new * PrintWriter(System.out) mitgiben, dann wuerde es wie zuvor * auf die Konsole ausgegeben. */ new Diamond(x).print(writer); writer.close(); } catch (IOException e) { e.printStackTrace(); } } else if (zeile.equalsIgnoreCase("Ö")) { System.out.println("Wird gemacht..."); scanner = new Scanner(file); while (scanner.hasNextLine()) { String line = scanner.nextLine(); System.out.println(line); } } else { System.out.println("Falsche Eingabe: " + zeile); } } } Die alte Diamond-Klasse, erweitert um den Writer, auf den geschrieben werden soll: public class Diamond { private int rows; public Diamond(int rows) { this.rows = rows; } void print(Writer writer) throws IOException { if (rows % 2 != 0) { for (Integer row = 1, stars = 1; row <= rows / 2 + 1; row++, stars += 2) { int blanks = rows - stars; print(' ', blanks / 2, writer); print('*', stars, writer); writer.write("\\n"); //hier nur ein backslash } for (Integer row = 1, stars = rows-2; row < rows / 2 + 1; row++, stars -= 2) { int blanks = rows - stars; print(' ', blanks / 2, writer); print('*', stars, writer); writer.write("\\n"); //hier nur ein backslash } } else } System.out.println("Bitte eine ungerade Zahl wählen!"); private void print(char c, int n, Writer writer) throws IOException { for (Integer i = 1; i <= n; i++) { writer.write(c); } } }