Java - Material - 2

Hier finden sich die besprochenen Java Programme des Sommersemesters 2009 ohne weiteren Kommentar.

Beispiel: Kontenverzeichnis, ohne generische Typen

import java.util.HashMap;
import java.util.Map;
public class KontenObject {
        // keys = integer, values = double
        private Map konten;

        public KontenObject() {
                konten = new HashMap();
        }

        public double buchen(int n, double b){
                double s = 0.0;
                double w = 0.0;
                Object ow = konten.get(n);
                if ( ow != null ) {
                    w = (Double) ow;
                }
                s = w + b;
                konten.put(n,s);
                return s;
        }

        public double stand(int n) {
                Object ow = konten.get(n);
                if ( ow != null ) {
                     return (Double) ow;
                } else { 
                     return 0.0;
                }
    }
}

Beispiel:

public class KontenObjectTest {
        public static void main(String[] args) {
                KontenTypen bank = new KontenTypen();
                bank.buchen(13,0.0);
                bank.buchen(11,0.0);
                System.out.println("bank(anfang) = " + bank);
                bank.buchen(13, 20.0);
                bank.buchen(11,-20.0);
                bank.buchen(17,  2.0);
                System.out.println("bank(ende) = " + bank);
        }

        public static void nomain(String[] args) {
                KontenObject bank = new KontenObject();
                bank.buchen(13,0.0);
                bank.buchen(11,0.0);
                System.out.println("stand(13) = " 
                                + bank.stand(13));
                System.out.println("stand(11) = " 
                                + bank.stand(11));
                bank.buchen(13, 20.0);
                bank.buchen(11,-20.0);
                System.out.println("stand(13) = " 
                                + bank.stand(13));
                System.out.println("stand(11) = " 
                                + bank.stand(11));
        }
}

Beispiel: Kontenverzeichnis mit generischen Datenypen

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class KontenTypen {
        // keys = integer, values = double
        // festlegung: keys haben typ Integer
        //             values haben typ Double
        private Map<Integer,Double> konten;

        public KontenTypen() {
                //konten = new HashMap<Integer,Double>();
                konten = new TreeMap<Integer,Double>();
        }

        public double buchen(int n, double b){
                double s = 0.0;
                double w = 0.0;
                Double ow = konten.get(n); // jetzt als typ
                if ( ow != null ) {
                    w = ow; // kein cast mehr notwendig
                }
                s = w + b;
                konten.put(n,s);
                return s;
        }

        public double stand(int n) {
                Object ow = konten.get(n);
                if ( ow != null ) {
                    return (Double) ow;
                } else { 
                    return 0.0;
                }
        }

        // Prüfung, ob die Summe aller Stände 0.0 ist 
        public boolean pruefe() {
                Collection<Double> werte = konten.values();
                double summe = 0.0;
                for ( Double w : werte ) { // for statt Iterator
                     summe += w;
                }
                if ( Math.abs(summe) <= 1.0E-10 ) { 
                     // wegen Rundungsfehler kein summe == 0.0
                     return true;
                } else {
                     return false;
                }
        }

        public String toString(int n) {
                String s = "<Konto ";        
                s += "nr='" + n + "'";
                s += " stand='" + stand(n) + "'";
                s += " />";
                return s;
        }

        public String toString() {
                String s = "\n<Konten geprueft='" +
                           pruefe() + "' >\n";
                // hole alle Schlüssel aus der Abbildung
                Set<Integer> nummern = konten.keySet();
                //s += nummern + "\n";
                // hole was für die Schleife
                // 1. einen Iterator
                Iterator<Integer> it = nummern.iterator();
                // 2. hole Schlüssel mit next()
                while ( it.hasNext() ) {
                       Integer i = it.next();
                       s += toString(i) + "\n";
                }
                s += "</Konten>\n";
                return s;
    }
}

Beispiel: Version mit List statt Set

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class KontenTypen {
        // keys = integer, values = double
        // festlegung: keys haben typ Integer
        //             values haben typ Double
        private Map<Integer,Double> konten;

        public KontenTypen() {
                //konten = new HashMap<Integer,Double>();
                konten = new TreeMap<Integer,Double>();
        }

        public double buchen(int n, double b){
                double s = 0.0;
                double w = 0.0;
                Double ow = konten.get(n); // jetzt als typ
                if ( ow != null ) {
                    w = ow; // kein cast mehr notwendig
                }
                s = w + b;
                konten.put(n,s);
                return s;
        }

        public double stand(int n) {
                Object ow = konten.get(n);
                if ( ow != null ) {
                    return (Double) ow;
                } else { 
                    return 0.0;
                }
        }

        // Prüfung, ob die Summe aller Stände 0.0 ist 
        public boolean pruefe() {
                //Collection<Double> werte = konten.values();
                // will List<Double> haben 
                List<Double> werte = new ArrayList<Double>();
                werte.addAll( konten.values() );
                double summe = 0.0;
                for ( Double w : werte ) { // for statt Iterator
                     summe += w;
                }
                if ( Math.abs(summe) <= 1.0E-10 ) { 
                    // wegen Rundungsfehler kein summe == 0.0
                    return true;
                } else {
                    return false;
                }
        }

        public String toString(int n) {
                String s = "<Konto ";           
                s += "nr='" + n + "'";
                s += " stand='" + stand(n) + "'";
                s += " />";
                return s;
        }

        public String toString() {
                String s = "\n<Konten geprueft='" +
                        pruefe() + "' >\n";
                // hole alle Schlüssel aus der Abbildung
                Set<Integer> nummern = konten.keySet();
                //s += nummern + "\n";
                // hole was für die Schleife
                // 1. einen Iterator
                Iterator<Integer> it = nummern.iterator();
                // 2. hole Schlüssel mit next()
                while ( it.hasNext() ) {
                       Integer i = it.next();
                       s += toString(i) + "\n";
                }
                s += "</Konten>\n";
                return s;
        }
}

Beispiel: mit eigener Klasse für einen Konto-Datensatz

import java.util.Date;

public class KontenRecord {

        String inhaber;
        double ueberziehungsKredit;
        Date datum;
        double stand;
        int konditionen;
        String bemerkungen;

        // constructor wird immer gebraucht
        public KontenRecord(
                        String inhaber,
                        double kredit,
                        int kond,
                        double stand,
                        String bem                      
                        ) {
                this.inhaber = inhaber;
                this.ueberziehungsKredit = kredit;
                this.konditionen = kond;
                this.stand = stand;
                this.bemerkungen = bem;
                this.datum = new Date();
        }

        public void buche(double b) {
                stand += b;
        }

        // wird immer gebraucht
        public String toString() {
                String s = "<Record>\n";
                s += "<Inhaber>" + inhaber + "</Inhaber>\n";
                s += "<Stand>" + stand + "</Stand>\n";
                // Aufgabe: die restlichen Info angeben
                s += "</Record>\n";
                return s;
        }
}

Beispiel:

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class KontenMitRecord {
        // keys = integer, values = double
        // festlegung: keys haben typ Integer
        //             values haben typ KontenRecord
        private Map<Integer,KontenRecord> konten;

        public KontenMitRecord() {
                //konten = new HashMap<Integer,KontenRecord>();
                konten = new TreeMap<Integer,KontenRecord>();
        }

        public double buchen(int n, double b){
                KontenRecord ow = konten.get(n); // jetzt als typ
                if ( ow != null ) {
                    ow.buche(b); 
                konten.put(n,ow);
                }
                return ow.stand;
        }

        public double stand(int n) {
                KontenRecord ow = konten.get(n);
                if ( ow != null ) {
                    return ow.stand;
                } else { 
                    return 0.0;
                }
        }

        // Prüfung, ob die Summe aller Stände 0.0 ist 
        public boolean pruefe() {
                Collection<KontenRecord> werte = konten.values();
                double summe = 0.0;
                for ( KontenRecord w : werte ) { // for statt Iterator
                     summe += w.stand;
                }
                if ( Math.abs(summe) <= 1.0E-10 ) { 
                    // wegen Rundungsfehler kein summe == 0.0
                    return true;
                } else {
                    return false;
                }
        }

        public String toString(int n) {
                String s = "<Konto ";           
                s += "nr='" + n + "' >\n";
                s += konten.get(n); // toString()
                s += "</Konto>";
                return s;
        }

        public String toString() {
                String s = "\n<Konten geprueft='" +
                           pruefe() + "' >\n";
                // hole alle Schlüssel aus der Abbildung
                Set<Integer> nummern = konten.keySet();
                //s += nummern + "\n";
                // hole was für die Schleife
                // 1. einen Iterator
                Iterator<Integer> it = nummern.iterator();
                // 2. hole Schlüssel mit next()
                while ( it.hasNext() ) {
                      Integer i = it.next();
                      s += toString(i) + "\n";
                }
                s += "</Konten>\n";
                return s;
        }

        public void neuesKonto(int i, KontenRecord m) {
                if ( konten.get(i) != null ) {
                    throw new IllegalArgumentException("Konto gibt es schon");
                }
                konten.put(i,m);                
        }
}

Beispiel:

public class KontenObjectTest {
        public static void main(String[] args) {
                KontenMitRecord bank = new KontenMitRecord();
                System.out.println("bank(anfang) = " + bank);
                KontenRecord maier = new KontenRecord(
                        "Ingo Maier", 0.0, 1, 0.0, "keine"
                        );
                KontenRecord king = new KontenRecord(
                        "Helmut King", 0.0, 1, 0.0, "keine"
                        );
                bank.neuesKonto(17,maier);
                bank.neuesKonto(4711,king);
                bank.buchen(17,   20.0);
                bank.buchen(4711,-20.0);
                System.out.println("bank(ende) = " + bank);
        }
}

Aufgaben:

Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.

  1. Schreiben Sie KontenObject mit Typ-Paramtern für die Map Datenstruktur um. Das Ergebniss sollte wie KontenTypen aussehen.

  2. Schreiben Sie KontenTypen so um, dass List anstelle von Set und Collection verwendet wird. Lesen Sie dazu die Java API Dokumentation des Packets java.util. Nochmal gestellt für toString().

  3. Vervollständigen Sie toString() von KontenRecord.


Beispiel: Ein- und Ausgabe von Konten-Objekten in Dateien.

import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class ObjectEinlesen extends ObjectInputStream {
  public ObjectEinlesen(String dateiName) throws IOException {
          super( new FileInputStream(dateiName) );
  }
}

Beispiel:

import java.io.ObjectOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ObjectAusgabe extends ObjectOutputStream {
  public ObjectAusgabe(String name) throws IOException { 
      super( new FileOutputStream(name) );
  } 
}

Beispiel:

import java.io.Serializable;
import java.util.Date;
public class KontenRecord implements Serializable {
   // Rest ist gleich
}

Beispiel:

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class KontenMitRecord {
        // keys = integer, values = double
        // festlegung: keys haben typ Integer
        //             values haben typ KontenRecord
        private Map<Integer,KontenRecord> konten;
        public KontenMitRecord() {
                //konten = new HashMap<Integer,KontenRecord>();
                konten = new TreeMap<Integer,KontenRecord>();
        }
        public int size() {
                return konten.size();
        }
        public double buchen(int n, double b){
                KontenRecord ow = konten.get(n); // jetzt als typ
                if ( ow != null ) {
                ow.buche(b); 
                konten.put(n,ow);
                }
                return ow.stand;
        }
        public double stand(int n) {
                KontenRecord ow = konten.get(n);
                if ( ow != null ) {
                    return ow.stand;
                } else { 
                    return 0.0;
                }
        }
        // Prüfung, ob die Summe aller Stände 0.0 ist 
        public boolean pruefe() {
                Collection<KontenRecord> werte = konten.values();
                double summe = 0.0;
                for ( KontenRecord w : werte ) { // for statt Iterator
                     summe += w.stand;
                }
                if ( Math.abs(summe) <= 1.0E-10 ) { 
                    // wegen Rundungsfehler kein summe == 0.0
                    return true;
                } else {
                    return false;
                }
        }
        public String toString(int n) {
                String s = "<Konto ";           
                s += "nr='" + n + "' >\n";
                s += konten.get(n); // toString()
                s += "</Konto>";
                return s;
        }
        public String toString() {
                String s = "\n<Konten geprueft='" +
                        pruefe() + "' >\n";
                // hole alle Schlüssel aus der Abbildung
                Set<Integer> nummern = konten.keySet();
                //s += nummern + "\n";
                // hole was für die Schleife
                // 1. einen Iterator
                Iterator<Integer> it = nummern.iterator();
                // 2. hole Schlüssel mit next()
                while ( it.hasNext() ) {
                       Integer i = it.next();
                       s += toString(i) + "\n";
                }
                s += "</Konten>\n";
                return s;
        }
        public void neuesKonto(int i, KontenRecord m) {
                if ( konten.get(i) != null ) {
                    throw new IllegalArgumentException("Konto gibt es schon");
                }
                konten.put(i,m);                
        }
        public void textSpeichern(String dateiName) throws IOException {
                PrintWriter pw = new PrintWriter(dateiName);
                pw.println( toString() );
                pw.close();
        }
        public void speichern(String dateiName) throws IOException {
                ObjectAusgabe ow = new ObjectAusgabe(dateiName);
                ow.writeObject( konten );
                ow.close();
        }
        public void laden(String dateiName) 
                    throws IOException, ClassNotFoundException {
                ObjectEinlesen or = new ObjectEinlesen(dateiName);
                Map<Integer,KontenRecord> k = 
                        (Map<Integer, KontenRecord>) or.readObject();
                or.close();
                konten = k;
        }
}

Beispiel:

import java.io.IOException;

public class KontenObjectTest {
        public static void main(String[] args) {
                KontenMitRecord bank = new KontenMitRecord();
                String datei = "eineBankDatei.stream";
                if ( args.length > 0 ) {
                    datei = args[0];
                }
                try {
                    bank.laden(datei);
                } catch (IOException e) {
                    System.out.println("Fehler: " + e);
                    //return; // Aufgabe: Wie geht das beim ersten mal?
                } catch (ClassNotFoundException e) {
                    System.out.println("Fehler: " + e);
                    return;
                }
                System.out.println("bank(anfang) = " + bank);
                if ( bank.size() == 0 ) { // initialisiere
                    KontenRecord maier = new KontenRecord(
                        "Ingo Maier", 0.0, 1, 0.0, "keine"
                        );
                    KontenRecord king = new KontenRecord(
                        "Helmut King", 0.0, 1, 0.0, "keine"
                        );
                    bank.neuesKonto(17,maier);
                    bank.neuesKonto(4711,king);
                }
                bank.buchen(17,   20.0);
                bank.buchen(4711,-20.0);
                System.out.println("bank(ende) = " + bank);
                try {
                     bank.speichern( datei );
                } catch(IOException e) {
                     System.out.println("Fehler " + e);
                     // normal hier nicht enden lassen sondern 
                     // neuer Versuch
                     // Aufgabe: mit while-Schleife und Nachfrage
                }
        }
}

Aufgaben:

Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.

  1. Ürarbeiten Sie die Methode main() der Klasse KontenObjectTest:

  2. Wenn beim ersten Aufruf des Programms die Datei noch leer ist, sollen die Konten geeignet initialisiert werden.

  3. Wenn das Speichern in der Ausgabe-Datei ein Fehler auftritt, soll die Benutzerin solange gefragt werden was zu tun ist, bis das Problem behoben wurde.

  4. Entwickeln Sie eine Methode textLaden(String dateiName) der Klasse KontenMitRecord, so dass die Ausgabe der Methode textSpeichern(String dateiName) wieder eingelesen werden kann. Bemerkung: Kann einige Tage zur Bearbeitung dauern.

  5. Lernen Sie das Java API for XML Processing (JAXP) und verwenden Sie es bei der Implementierung von textLaden(). Bemerkung: Kann einige Tage zur Bearbeitung dauern.

  6. Entwickeln Sie eine grafische Benutzeroberfläche für die Klasse KontenMitRecord. In einer Maske sollen die notwendigen Informationen für den Konstuktor der Klasse KontenRecord erfasst werden und eine Kontonummer vergeben werden. Zum Speichern und Laden können die vorhandenen Methoden als Aktion an einen Button oder Menuepunkt gebunden werden.

Beispiel: Verzeichnis von Kontonummern und Kontendatensätzen in einer TreeMap.

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
 * Verzeichnis von Kontonummern und Kontendatensätzen.
 * 
 * @author usr336b
 */
public class KontenMitRecord {
        // keys = integer, values = double
        // festlegung: keys haben typ Integer
        //             values haben typ KontenRecord
        private Map<Integer,KontenRecord> konten;

        /**
         * Dieser Konstruktor initialisiert das Verzeichnis.
         */
        public KontenMitRecord() {
                //konten = new HashMap<Integer,KontenRecord>();
                konten = new TreeMap<Integer,KontenRecord>();
        }

        /**
         * Die Anzahl der vorhandenen Konten.
         * @return die Anzahl der Konten.
         */
        public int size() {
                return konten.size();
        }

        /**
         * Methode zur Ausführung einer Buchung.
         * @param n die Kontonummer.
         * @param b der zu addierende Betrag.
         * @return den neuen Kontostand.
         */
        public double buchen(int n, double b){
                KontenRecord ow = konten.get(n); // jetzt als typ
                if ( ow != null ) {
                    ow.buche(b); 
                    konten.put(n,ow);
                }
                return ow.stand;
        }
        
        /**
         * Methode zum Anzeigen den Kontostandes.
         * @param n die Kontonummer.
         * @return Kontestand für Konto Nummer n.
         */
        public double stand(int n) {
                KontenRecord ow = konten.get(n);
                if ( ow != null ) {
                    return ow.stand;
                } else { 
                    return 0.0;
                }
        }
    
    /**
     * Prüfung der doppelten Buchführung. 
     * Test ob die Summe aller Kontostände 0.0 ist.
     * @return true falls die Prüfung erfolgreich ist,
     *         sonst false.
     */
    public boolean pruefe() {
        Collection<KontenRecord> werte = konten.values();
        double summe = 0.0;
        for ( KontenRecord w : werte ) { // for statt Iterator
             summe += w.stand;
        }
        if ( Math.abs(summe) <= 1.0E-10 ) { 
                // wegen Rundungsfehler kein summe == 0.0
                return true;
        } else {
            return false;
        }
    }
    
    /**
     * Verwandle ein Konto in eine XML-Zeichenkette.
     * Hier kommt die Beschreibung der Datenstruktur...
     * <pre>
     * &lt;Konto nr="n" &gt;
     * ...
     * &lt;/Konto&gt;
     * </pre>
     * @param n die Kontonummer.
     * @return Zeichenkette mit XML Datensatz.
     */
    public String toString(int n) {
        String s = "<Konto ";           
        s += "nr='" + n + "' >\n";
        s += konten.get(n); // toString()
        s += "</Konto>";
        return s;
    }
    
    /**
     * Verwandle alle Konten in eine XML-Zeichenkette.
     * @return Zeichenkette mit XML-Darstellung aller Konten.
     */
    public String toString() {
        String s = "\n<Konten geprueft='" +
                        pruefe() + "' >\n";
        // hole alle Schlüssel aus der Abbildung
        Set<Integer> nummern = konten.keySet();
        //s += nummern + "\n";
        // hole was für die Schleife
        // 1. einen Iterator
        Iterator<Integer> it = nummern.iterator();
        // 2. hole Schlüssel mit next()
        while ( it.hasNext() ) {
                Integer i = it.next();
                s += toString(i) + "\n";
        }
        s += "</Konten>\n";
        return s;
    }

    /**
     * Lege ein neues Konto an.
     * @param i die Kontonummer.
     * @param m der Kontendatensatz.
     */
     public void neuesKonto(int i, KontenRecord m) {
        if ( konten.get(i) != null ) {
            throw new IllegalArgumentException("Konto gibt es schon");
        }
        konten.put(i,m);                
     }

        /**
         * Speichere den Inhalt des Verzeichnisses 
         * in einer Text-Datei.
         * @param dateiName der Name der Datei.
         * @throws IOException falls etwas schief geht.
         */
        public void textSpeichern(String dateiName) throws IOException {
                PrintWriter pw = new PrintWriter(dateiName);
                pw.println( toString() );
                pw.close();
        }
        
        /**
         * Speichere den Inhalt des Verzeichnisses
         * in einer Serialisierten Object-Datei. 
         * @param dateiName der Name der Datei.
         * @throws IOException falls etwas schief geht.
         */
        public void speichern(String dateiName) throws IOException {
                ObjectAusgabe ow = new ObjectAusgabe(dateiName);
                ow.writeObject( konten );
                ow.close();
        }
        
        /**
         * Lade ein Verzeichnis aus einer Serialisierten
         * Object-Datei.
         * <b>Achtung:</b> der alte Inhalt wird überschrieben.
         * @param dateiName der Name der Datei.
         * @throws IOException falls etwas schief geht.
         * @throws ClassNotFoundException falls eine Klasse 
         * nicht gefunden wird.
         */
        public void laden(String dateiName) 
                    throws IOException, ClassNotFoundException {
                ObjectEinlesen or = new ObjectEinlesen(dateiName);
                Map<Integer,KontenRecord> k = 
                        (Map<Integer, KontenRecord>) or.readObject();
                or.close();
                konten = k;
        }
}

Beispiel: Kontenverzeichnis mit vollständigerem Konto-Datensatz.

import java.io.Serializable;
import java.util.Date;

/**
 * Datensatz für ein Konto.
 * Hier werden alle interessanten Felder für 
 * ein Konto definiert.
 * @author usr336b
 */
public class KontenRecord implements Serializable {
        String inhaber;
        double ueberziehungsKredit;
        Date datum;
        double stand;
        int konditionen;
        String bemerkungen;

    /**
     * Kontruktor für den Kontendatensatz.
     * @param inhaber der Eigentümer des Kontos.
     * @param kredit der Kreditrahmen für das Konto.
     * @param kond weitere Konditionen.
     * @param stand der aktuelle Kontostand.
     * @param bem weitere Bemerkungen.
     */ 
        public KontenRecord(
                        String inhaber,
                        double kredit,
                        int kond,
                        double stand,
                        String bem                      
                        ) {
                this.inhaber = inhaber;
                this.ueberziehungsKredit = kredit;
                this.konditionen = kond;
                this.stand = stand;
                this.bemerkungen = bem;
                this.datum = new Date();
        }
        
        /**
         * Buchen eines Betrages auf den Kontendatensatz.
         * @param b dieser Betrag wird auf den aktuellen 
         * Kontostand addiert.
         */
        public void buche(double b) {
                stand += b;
        }
        
        /**
         * Wandle den Datensatz in eine Zeichenkette um.
         * @return die Zeichenkette.
         */
        public String toString() {
                String s = "<Record>\n";
                      s += "<Inhaber>" + inhaber + "</Inhaber>\n";
                      s += "<Stand>" + stand + "</Stand>\n";
                      // Aufgabe: die restlichen Info angeben
                      s += "</Record>\n";
                return s;
        }
}

Beispiel:

import java.io.ObjectOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Hilfsklasse für ObjectOutputStream in eine Datei.
 * @author usr336b
 */
public class ObjectAusgabe extends ObjectOutputStream {

        /**
         * Kontruktor zur Angabe eines Dateinamens.
         * @param name der Name einer Datei.
         * @throws IOException falls was schief geht.
         */
        public ObjectAusgabe(String name) throws IOException { 
          super( new FileOutputStream(name) );
        } 
}

Beispiel:

import java.io.ObjectInputStream;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * Hilfsklasse für ObjectInputStream aus einer Datei.
 * @author usr336b
 */
public class ObjectEinlesen extends ObjectInputStream {

        /**
         * Konstruktor mit Angabe des Dateinamens.
         * @param dateiName der Name der Datei.
         * @throws IOException falls was schief geht.
         */
        public ObjectEinlesen(String dateiName) throws IOException {
          super( new FileInputStream(dateiName) );
        }
}

Beispiel:

import java.io.IOException;

/**
 * Eine Klasse zum Testen der Konten Anwendung.
 * Die <code>main()</code> Methode erzeugt eine bank 
 * und führt einige Testbuchungen durch.
 * @author usr336b
 */
public class KontenObjectTest {

        /**
         * Die wichtige <code>main()</code> Methode wird 
         * von der Laufzeitumgebung aufgerufen. 
         * @param args ein Array von Kommandozeilen Parametern.
         */
        public static void main(String[] args) {
                KontenMitRecord bank = new KontenMitRecord();
                String datei = "eineBankDatei.stream";
                if ( args.length > 0 ) {
                    datei = args[0];
                }
                try {
                     bank.laden(datei);
                } catch (IOException e) {
                    System.out.println("Fehler: " + e);
                    //return; // Aufgabe: Wie geht das beim ersten mal?
                } catch (ClassNotFoundException e) {
                    System.out.println("Fehler: " + e);
                    return;
                 }
                System.out.println("bank(anfang) = " + bank);
                if ( bank.size() == 0 ) { // initialisiere
                    KontenRecord maier = new KontenRecord(
                        "Ingo Maier", 0.0, 1, 0.0, "keine"
                        );
                    KontenRecord king = new KontenRecord(
                        "Helmut King", 0.0, 1, 0.0, "keine"
                        );
                    bank.neuesKonto(17,maier);
                    bank.neuesKonto(4711,king);
                }
                bank.buchen(17,   20.0);
                bank.buchen(4711,-20.0);
                System.out.println("bank(ende) = " + bank);
                try {
                     bank.speichern( datei );
                } catch(IOException e) {
                    System.out.println("Fehler " + e);
                    // normal hier nicht enden lassen sondern 
                    // neuer Versuch
                    // Aufgabe: mit while-Schleife und Nachfrage
                }
        }
}

Ergebnis von Javadoc

Aufgaben:

Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.

  1. Vervollständigen Sie die Javadoc-Kommentare bei den restlichen Klassen.


Beispiel: Thread Erzeugung und Nutzung am Beispiel von Rennautos als Threads

import java.util.List;

public class RennAuto extends Thread {
    String auto;
    String fahrer;
    List<RennAuto> platz;

    /**
     * Ein Auto-Thread wird mit 
     * einem Fahrer und Auto initialisiert.
     * @param p Liste für den Zieleinlauf
     * @param a das Auto
     * @param f der Fahrer oder die Fahrerin
     */
     public RennAuto(List<RennAuto> p, String a, String f) {
                auto = a;
                fahrer = f;
                platz = p;
     }

     public String toString() {
                return fahrer + " mit " + auto;
     }

     /**
      * In dieser Methode passiert die Abarbeitung  
      */
     public void run() {
                System.out.println(this + " gestartet");
                // das Rennen fahren
                rennenFahren(500);
                motorSchaden();
                rennenFahren(500);
                synchronized (platz) { 
                   System.out.println(this.toString() + " im Ziel angekommen");
                   platz.add(this);
                }
     }

     void motorSchaden() {
                double w = Math.random(); // 0 <= w <= 1.0
                if ( w > 0.5 ) {
                        throw new RuntimeException("Motor von " + 
                                        auto + " ist kaputt");
                }
     }

     void rennenFahren(int max){
               // Math.random() liefert double zwischen 0.0 und 1.0
        try {
               sleep( (int)(max*Math.random()) );
        } catch (InterruptedException e) {
               System.out.println("Dies sollte nicht passieren "+e);
        }
     }
}
//Thread.currentThread().sleep( (int)(max*Math.random()) );

Beispiel:

import java.util.ArrayList;
import java.util.List;
public class FormelEins {
        public static void main(String[] args) {
                List<RennAuto> platz = new ArrayList<RennAuto>();
                // Erzeugen, starten und stoppen von RennAutos
                Thread t1 = new RennAuto(platz,"Ferrari","Schuhmacher");
                Thread t2 = new RennAuto(platz,"RedBull","Vettel");
                Thread t3 = new RennAuto(platz,"McLarrenMercedes","Hamilton");
                System.out.println("Autos sind bereit");
                t1.start(); t2.start(); t3.start();
                System.out.println("Rennen gestartet");
                try {
                        t1.join(); t2.join(); t3.join();
                } catch(InterruptedException e) {
                        System.out.println("Fehler: " + e);
                }
                System.out.println("Rennen beendet");
                System.out.println("Platzierung " + platz);
                //System.exit(0);
        }
}

Aufgaben:

Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.

  1. Verwenden Sie ein elementares Array oder eine ArrayList für die Speicherung der erzeugten Threads. Starten Sie alle Threads in einer Schleife über die Array-Elemente und warten Sie ebenso auf die Terminierung aller Threads in einer Schleife.

  2. Erweitern Sie den Konstruktor von RennAuto um einen Parameter für die Höchstgeschwindigkeit und für die Ausfallwahrscheinlichkeit des Motors.

    Berechnen Sie das Argument für die Methode rennenFahren() nach der Formel "1000 - Höchstgeschwindigkeit".

    Erweitern Sie die Parameterliste von motorSchaden() um einen double Wert, also zu motorSchaden(double pm). Verwenden Sie diesen Wert Anstelle des festen Wertes 0.5.

  3. Führen Sie eine Text-Datei für die Teilnehmer eines Rennens ein. In der Datei soll der Name des Fahrers und das Auto mit weiteren Eigenschaften abgelegt sein. Die Werte sollen durch Komma getrennt werden. Zum Beispiel

      # Fahrer, Auto, Höchstgeschwindigkeit, Motorschaden Wahrscheinlichkeit, ...
      Vettel, Red Bull, 230, 0.2, ...
      Hamilton, McLarenMercedes, 220, 0.3, ...
      Schuhmacher, Ferrari, 220, 0.2, ...
       ...
      

    Lesen Sie zu Programmbeginn diese Datei ein und generieren Sie aus den Infos in jeder Zeile eine RennAuto Klasse.


Beispiel: sequentielle und parallele Matrizen-Multiplikation

public class SeqMult {

    public void multiply(double[][] C, 
                         double[][] A, 
                         double[][] B) {
        for (int i=0; i < A.length; i++) {
             for (int j=0; j < B[0].length; j++) {
                 double c = 0.0;
                 for (int k=0; k < B.length; k++) {
                      c += A[i][k] * B[k][j];
                 }
                 C[i][j] = c;
             }
        }
    }   
}

Beispiel:

import java.util.ArrayList;
import java.util.List;

public class ParMult {

    public void multiply(double[][] C, double[][] A, 
                         double[][] B) {
        List<Thread> threads = new ArrayList<Thread>();
        for (int i=0; i < A.length; i++) {
            Thread t = new ZeilenMult(C,A,B,i);
            t.start();
            threads.add(t);
        }
        for (Thread t : threads) {
                try {
                    t.join();
                } catch(Exception e) {
                    System.out.println("Exception: " +e);
                }
        }
    }   
}

class ZeilenMult extends Thread {

        double[][] A; double[][] B; double[][] C;
        int i;

        ZeilenMult(double[][] C, double[][] A, double[][] B, 
                           int i) {
                this.C = C; this.A = A; this.B = B;
                this.i = i;
        }

        public void run() {
          for (int j=0; j < B[0].length; j++) {
              double c = 0.0;
              for (int k=0; k < B.length; k++) {
                   c += A[i][k] * B[k][j];
              }
              C[i][j] = c;
          }
        }
}

Beispiel:

import java.util.ArrayList;
import java.util.List;

public class ParProcMult {

    int anzahl;

    ParProcMult(int anzahl) {
        this.anzahl = anzahl;
    }

    public void multiply(double[][] C, double[][] A, 
                         double[][] B) {
        List<Thread> threads = new ArrayList<Thread>();
        for (int i=0; i < anzahl; i++) {
            Thread t = new ZeilenMultProc(C,A,B,i,anzahl);
            t.start();
            threads.add(t);
        }
        for (Thread t : threads) {
                try {
                    t.join();
                } catch(Exception e) {
                    System.out.println("Exception: " +e);
                }
        }
    }   
}

class ZeilenMultProc extends Thread {

        double[][] A; double[][] B; double[][] C;
        int ii;
        int anzahl;

        ZeilenMultProc(double[][] C, double[][] A, double[][] B, 
                       int i, int anzahl) {
                this.C = C; this.A = A; this.B = B;
                this.ii = i; this.anzahl = anzahl;
        }

        public void run() {
            int todo = A.length/anzahl;
            for ( int i = todo*ii; i < todo*(ii+1) ; i++) {
                for (int j=0; j < B[0].length; j++) {
                     double c = 0.0;
                     for (int k=0; k < B.length; k++) {
                          c += A[i][k] * B[k][j];
                     }
                     C[i][j] = c;
                }
             }
        }
}

Beispiel:

public class MatMult {

    public static double[][] randomMat(int n){
        double[][] mat = new double[n][n];
        for ( int i = 0; i < n; i++ ) {
                for ( int j = 0; j < n; j++ ) {
                        mat[i][j] = Math.random();
                }
        }
        return mat;
    }

    public static double[][] zeroMat(int n){
        double[][] mat = new double[n][n];
        for ( int i = 0; i < n; i++ ) {
                for ( int j = 0; j < n; j++ ) {
                        mat[i][j] = 0.0;
                }
        }
        return mat;
    }

    public static double[][] oneMat(int n){
        double[][] mat = new double[n][n];
        for ( int i = 0; i < n; i++ ) {
                for ( int j = 0; j < n; j++ ) {
                    if ( i == j ) {
                        mat[i][j] = 1.0;
                    } else {
                        mat[i][j] = 0.0;
                    }
                }
        }
        return mat;
    }

    public static void printMat(double[][] mat){
        for ( int i = 0; i < mat.length; i++ ) {
                for ( int j = 0; j < mat[0].length; j++ ) {
                    System.out.print(mat[i][j]);
                    if ( j < mat[0].length-1 ) {
                        System.out.print(", ");
                    }
                }
                System.out.println();
        }
        System.out.println();
    }

    public static boolean equalMat(double[][] A, double[][] B ){
        double eps = Double.MIN_VALUE*10.0;
        for ( int i = 0; i < A.length; i++ ) {
             for ( int j = 0; j < A[0].length; j++ ) {
                  double b = Math.abs(A[i][j]-B[i][j]);
                  if ( b >= eps) {
                          return false;
                  }
             }
        }
        return true;
    }

    public static void main(String[] args) {
        int n = 1000;
        double[][] C = zeroMat(n);
        double[][] A = randomMat(n);
        double[][] B = randomMat(n);
        double[][] Cp = zeroMat(n);
        double[][] Cpp = zeroMat(n);
                
        SeqMult sm = new SeqMult();
        ParMult pm = new ParMult();
        ParProcMult pmp = new ParProcMult(100);
                
        System.out.println("Matrix A = ");
        //printMat(A);
        System.out.println("Matrix B = ");
        //printMat(B);
                
        long sstart = System.currentTimeMillis();
        sm.multiply(C,A,B);
        long sstop = System.currentTimeMillis();
                
        long pstart = System.currentTimeMillis();
        pm.multiply(Cp,A,B);
        long pstop = System.currentTimeMillis();
        System.out.println("Matrix C = ");
                
        long ppstart = System.currentTimeMillis();
        pmp.multiply(Cpp,A,B);
        long ppstop = System.currentTimeMillis();
        System.out.println("Matrix C = ");
                
        //printMat(C);          
        System.out.println("seq      Zeit = " + (sstop-sstart));
        System.out.println("par      Zeit = " + (pstop-pstart));
        System.out.println("par proc Zeit = " + (ppstop-ppstart));
        System.out.println("gleich = " + equalMat(Cp,C));
        System.out.println("gleich = " + equalMat(Cpp,C));
        //System.out.println("eps = " + Double.MIN_VALUE);
        System.out.println("Anzahl CPUs = " + Runtime.getRuntime().availableProcessors());
    }
}

Aufgaben:

Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.

  1. Messen Sie die Performance dieser Implementierungen für verschiedene Matrixgrößen, für verschiedene Thread-Anzahlen und verschiedenen Rechnern mit einer und mehreren CPUs.

  2. Implementieren Sie ein Matrix-Benchmark Programm, mit dem Sie die Performance verschiedener Matrix Multiplikationsalgorithmen vergleichen können (analog zur Klasse MatMult).

    Vergleichen Sie die Algorithmen (der Methode multiply()) der folgenden Klassen:

    • SeqMult
    • ParMult
    • ParMultProc, bzw. ParProcMult
    • SeqMultBlock
    • ParMultProcBlock
    • SeqMultTrans
    • SeqMultBlockTrans
    • ParMultProcTrans
    • ParMultProcBlockTrans

    Die Klassen finden Sie hier.

    Erfassen Sie die wichtigsten Daten des Benchmark Rechners: CPU Typ, Anzahl CPUs, Geschwindigkeit, Caches (evtl. L1,L2,L3), Hauptspeicher, Java Version. Erstellen Sie eine Tabelle etwa wie folgt:

    Algorithmus Matrixgrösse Blockgrösse Thread Anzahl Rechenzeit in Sec
    ... ... ... ... ...

    Bemerkung: Kann einige Tage zur Bearbeitung dauern.

  3. Überlegen Sie wie Sie die Performance der Matrix-Multiplikation weiter verbessern können.


Beispiel: ein Konto, das sich parallel von mehreren Thredas aus benutzen lässt.

public class KontoSync {

    double stand;

    public KontoSync(double s) {
        this.stand = s;
    }

    public /*synchronized*/ void buchen(double b) {
        // mach was
        synchronized (this) {
                double a = stand;
                updateOtherThings(1000);
                a += b;
                stand = a;
        }
        // noch was
        }

    public double stand() {
        return stand;
    }

    public String toString(){
        return "" + stand();
    }

    void updateOtherThings(int max){
        // Math.random() liefert double zwischen 0.0 und 1.0
        try {
               Thread.currentThread().sleep( (int)(max*Math.random()) );
        } catch (InterruptedException e) {
               System.out.println("Dies sollte nicht passieren "+e);
        }
    }
}

Beispiel:

public class UeberweisungSync extends Thread {

    KontoSync a;
    KontoSync b;
    double betrag;

    public UeberweisungSync(KontoSync a, KontoSync b, double bb) {
        this.a = a;
        this.b = b;
        betrag = bb;
    }

    public void run () {
        a.buchen(-betrag);
        b.buchen(betrag);
    }
}

Beispiel:

public class FinanzSync {
        public static void main(String[] args) {
                KontoSync a = new KontoSync(120);
                KontoSync b = new KontoSync(80);
                System.out.println("start a = " + a);
                System.out.println("start b = " + b);
                Thread[] threads = new Thread[6];
                threads[0] = new UeberweisungSync(a,b,20);
                threads[1] = new UeberweisungSync(b,a,20);
                threads[2] = new UeberweisungSync(a,b,30);
                threads[3] = new UeberweisungSync(b,a,30);
                threads[4] = new UeberweisungSync(a,b,50);
                threads[5] = new UeberweisungSync(b,a,50);
                for ( int i = 0; i &lt; 6; i++ ) {
                        threads[i].start();
                }
                System.out.println("mitte a = " + a);
                System.out.println("mitte b = " + b);
                for ( int i = 0; i &lt; 6; i++ ) {
                        try { threads[i].join();
                        } catch(InterruptedException e) {
                                System.out.println("e = " + e);
                        }
                }               
                System.out.println("ende  a = " + a);
                System.out.println("ende  b = " + b);
        }
}

Beispiel: ein Konto, das nicht ins Minus geht, sondern wartet bis Geld eingegengen ist.

public class KontoPlus {
        // diese Konto Klasse bleibt immer im plus.
        // d.h. der Kontostand ist >= 0.

        double stand;
//      Object m = new Object(); // funktioniert

        public KontoPlus(double s) {
            if ( s < 0 ) {
                throw new IllegalArgumentException();
            }
           this.stand = s;
        }

        public /*synchronized*/ void buchen(double b) {
                // mach was
                synchronized (this) {
                    double a = stand + b; 
                    updateOtherThings(1000);
                    Thread t = Thread.currentThread();
                    while ( /*a < 0 */ -b > stand ) { // kein if !!!!!
                           System.out.println("warte auf Geld " + t);
                           try {
                                this.wait(); // blockiert unbedingt
                           } catch (InterruptedException e) {
                                e.printStackTrace();
                           }
                           System.out.println("warten beendet " + t);
                           a = stand + b;
                    }
                    if ( a >= 0 || a > stand ) {
                         System.out.println("sende notify " + t);
                         this.notifyAll(); //  
                    }
                    stand = a;
                }
                // noch was
        }

        public double stand() {
            return stand;
        }

        public String toString(){
            return "" + stand();
        }
 
        void updateOtherThings(int max){
                // Math.random() liefert double zwischen 0.0 und 1.0
                try {
                       Thread.currentThread().sleep( (int)(max*Math.random()) );
                } catch (InterruptedException e) {
                       System.out.println("Dies sollte nicht passieren "+e);
                }
        }
}

Beispiel:

public class UeberweisungPlus extends Thread {

            KontoPlus a;
            KontoPlus b;
            double betrag;

            public UeberweisungPlus(KontoPlus a, KontoPlus b, double bb) {
                this.a = a;
                this.b = b;
                betrag = bb;
            }

            public void run () {
                a.buchen(-betrag);
                b.buchen(betrag);
            }
}

Beispiel:

public class FinanzPlus {
                public static void main(String[] args) {
                        KontoPlus a = new KontoPlus(20);
                        KontoPlus b = new KontoPlus(80);
                        System.out.println("start a = " + a);
                        System.out.println("start b = " + b);
                        Thread[] threads = new Thread[6];
                        threads[0] = new UeberweisungPlus(a,b,20);
                        threads[1] = new UeberweisungPlus(b,a,20);
                        threads[2] = new UeberweisungPlus(a,b,30);
                        threads[3] = new UeberweisungPlus(b,a,30);
                        threads[4] = new UeberweisungPlus(a,b,50);
                        threads[5] = new UeberweisungPlus(b,a,20); // deadlock bei 20, 50 ist ok 
                        for ( int i = 0; i < 6; i++ ) {
                                threads[i].start();
                        }
                        System.out.println("mitte a = " + a);
                        System.out.println("mitte b = " + b);
                        for ( int i = 0; i < 6; i++ ) {
                                try { threads[i].join();
                                } catch(InterruptedException e) {
                                    System.out.println("e = " + e);
                                }
                        }               
                        System.out.println("ende  a = " + a);
                        System.out.println("ende  b = " + b);
                }
}

Beispiele: mit BlockingQueue aus java.util.concurrent

import java.util.List;

public class DVD {

        List<Double> liste; // Spieldauer der songs
        String name;        // Bezeichnung der DVD

        public DVD(String name, List<Double> liste) {
                this.name = name;
                this.liste = liste;
        }

        public String toString() {
                String s = "DVD(" + name;
                for ( Double d : liste ) {
                        s += ", " + d;
                }
                return s + ")";
        }

        public Double dauer() {
                double sum = 0.0;
                for ( Double d : liste ) {
                        sum += d; 
                }
                return sum;
        }
}

Beispiel:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;

public class DVDGenerator extends Thread {

    int anzahl;
    BlockingQueue<DVD> stapel;

    public DVDGenerator(BlockingQueue<DVD> stapel, int anzahl) {
        this.stapel = stapel;
        this.anzahl = anzahl;
    }

    public void run() {
        for ( int i = 0; i < anzahl; i++ ) {
             List<Double> zeiten = new ArrayList<Double>();
             int stueck = (int) (Math.random()*100);
             for ( int j = 0; j < stueck; j++ ) {
                double zeit = 1.0 + Math.random()*3.0;
                zeit = ((int)(zeit*100.0)/100.0);
                zeiten.add( zeit );
             }
             DVD abba = new DVD("abba-"+i,zeiten);
             try {
                 stapel.put(abba);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             System.out.println("abba = " + abba);
        }
    }
}

Beispiel:

import java.util.concurrent.BlockingQueue;

public class DVDSummator extends Thread {

   int anzahl;
   BlockingQueue<DVD> stapel;

   public DVDSummator(BlockingQueue<DVD> stapel, int anzahl) {
           this.stapel = stapel;
           this.anzahl = anzahl;
   }

   public void run() {
           double dauer = 0.0;
           for ( int i = 0; i < anzahl; i++ ) {
                   try {
                           DVD abba = stapel.take();
                           dauer += abba.dauer();
                   } catch (InterruptedException e) {
                           System.out.println("e = " + e);
                   }
           }
           System.out.println("dauer = " + dauer);
   }
}

Beispiel:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class DVDMain {

   public static void main(String[] args) {
        BlockingQueue<DVD> stapel = new ArrayBlockingQueue<DVD>(10);
        Thread gen = new DVDGenerator(stapel,20);
        gen.start();
        Thread sum1 = new DVDSummator(stapel,10);
        Thread sum2 = new DVDSummator(stapel,10);
        sum1.start();
        sum2.start();
        try {
             gen.join(); sum1.join(); sum2.join();
        } catch (InterruptedException e) {
             System.out.println("e = " + e);
        }
   }

}

Beispiel: neue Version mit Summation der Teil-Ergebnisse.

import java.util.concurrent.BlockingQueue;

public class DVDSummator extends Thread {

   int anzahl;
   BlockingQueue<DVD> stapel;
   double dauer = 0.0;

   public DVDSummator(BlockingQueue<DVD> stapel, int anzahl) {
           this.stapel = stapel;
           this.anzahl = anzahl;
   }

   public void run() {
           for ( int i = 0; i < anzahl; i++ ) {
                   try {
                           DVD abba = stapel.take();
                           dauer += abba.dauer();
                   } catch (InterruptedException e) {
                           System.out.println("e = " + e);
                   }
           }
           System.out.println("teil dauer = " + dauer);
   }
}

Beispiel:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class DVDMain {

    public static void main(String[] args) {
        BlockingQueue<DVD> stapel = new ArrayBlockingQueue<DVD>(10);      
        Thread gen = new DVDGenerator(stapel,3000);
        gen.start();
        Double dauer = 0.0;
        DVDSummator sum1 = new DVDSummator(stapel,1000);
        DVDSummator sum2 = new DVDSummator(stapel,1000);
        DVDSummator sum3 = new DVDSummator(stapel,1000);
        sum1.start();
        sum2.start();
        sum3.start();
        try {
             gen.join(); sum1.join(); sum2.join(); sum3.join();
        } catch (InterruptedException e) {
               System.out.println("e = " + e);
        }
        dauer += sum1.dauer;
        dauer += sum2.dauer;
        dauer += sum3.dauer;
        System.out.println("gesammte dauer = " + dauer);
        }
}

Aufgaben:

Ändern Sie das Verfahren, wie die Teil-Ergebnisse aufsummiert werden:

  1. Verlegen Sie die Summation in einen synchronized Bereich in jedem DVDSummator Thread. Definieren Sie dazu eine Container Klasse mit einer synchronisierten addTo() methode.

  2. Verwenden Sie eine synchonisierte Datenstruktur wie etwa ArrayBlockingQueue, um die Teilergebnisse in den Threads zu speichern und diese dann im Hauptprogramm zusammen zu addieren.


Beispiel: Netzwerk Programmierung mit einem einfachen Client-Server Programm.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class SimpleClient {

   public static void main(String[] args) {
       try {
            Socket s = new Socket("141.72.5.100",1337);
            System.out.println("connected to " + s);
            BufferedReader br = new BufferedReader(
                                   new InputStreamReader( s.getInputStream() ) );
            String zeile = br.readLine();
            System.out.println("Antwort vom Server " + zeile);
            PrintWriter pw = new PrintWriter(s.getOutputStream());
            pw.println("Hallo lieber Server");
            pw.close();
            br.close();
            s.close();
       } catch (UnknownHostException e) {
            e.printStackTrace();
       } catch (IOException e) {
            e.printStackTrace();
       }
   }
}

Beispiel: einfacher Server

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class SimpleServer {

   public static void main(String[] args) {
       try {
           ServerSocket se = new ServerSocket(1337);
           System.out.println("Server started = " + se);
           while ( true ) {
                 System.out.println("waiting ...");
                 Socket s = se.accept();
                 System.out.println("connection from " + s);
                 PrintWriter pw = new PrintWriter(s.getOutputStream());
                 pw.println("Hallo lieber Client");
                 BufferedReader br = new BufferedReader(
                                         new InputStreamReader( s.getInputStream() ) );
                 String zeile = br.readLine();
                 System.out.println("Antwort vom Client " + zeile);
                 br.close();
                 pw.close();
                 s.close();
           }
           //se.close();
       } catch (IOException e) {
               e.printStackTrace();
       }
   }
}

Beispiel: einfacher Server, funktionierende Version

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class SimpleServer {
        public static void main(String[] args) {
                try {
                     ServerSocket se = new ServerSocket(1337);
                     System.out.println("Server started = " + se);
                     while ( true ) {
                           System.out.println("waiting ...");
                           Socket s = se.accept();
                           System.out.println("connection from " + s);
                           PrintWriter pw = new PrintWriter(s.getOutputStream());
                           BufferedReader br = new BufferedReader(
                                  new InputStreamReader( s.getInputStream() ) );
                           pw.println("Hallo lieber Client");
                           pw.flush();
                           System.out.println("calling server readline ...");
                           String zeile = br.readLine();
                           System.out.println("Antwort vom Client " + zeile);
                           br.close();
                           pw.close();
                           s.close();
                     }
                     //se.close();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }
}

Beispiel: einfacher Client, funktionierende Version

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class SimpleClient {
    public static void main(String[] args) {
       try {
           Socket s = new Socket("141.72.5.100",1337);
           System.out.println("connected to " + s);
           PrintWriter pw = new PrintWriter(s.getOutputStream());
           BufferedReader br = new BufferedReader(
                           new InputStreamReader( s.getInputStream() ) );
           System.out.println("calling client readline ...");
           String zeile = br.readLine();
           System.out.println("Antwort vom Server " + zeile);
           pw.println("Hallo lieber Server");
           pw.flush();
           pw.close();
           br.close();
           s.close();
       } catch (UnknownHostException e) {
                   e.printStackTrace();
       } catch (IOException e) {
                   e.printStackTrace();
       }
    }
}

Beispiel: einfacher Web-Server

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
        public static void main(String[] args) {
                try {
                    ServerSocket se = new ServerSocket(8080);
                    System.out.println("Server started = " + se);
                    while ( true ) {
                           System.out.println("waiting ...");
                           Socket s = se.accept();
                           System.out.println("connection from " + s);
                           PrintWriter pw = new PrintWriter(s.getOutputStream());
                           BufferedReader br = new BufferedReader(
                                 new InputStreamReader( s.getInputStream() ) );

                           // http Protokoll: GET /path/file.ext
                           System.out.println("calling server readline ...");
                           String zeile = br.readLine();
                           System.out.println("Antwort vom Client " + zeile);
                           //br.close(); dies war ein fehler
                           if ( zeile.startsWith("GET ") ) {
                               String name = zeile.substring(4);
                               int i = name.indexOf(" ");
                               name = name.substring(1,i);
                               System.out.println("name = " + name);
                               BufferedReader datei = new BufferedReader(
                                        new FileReader(name));
                               System.out.println("datei = " + datei);
                               while (true) {
                                   String line = datei.readLine();
                                   System.out.println("gelesen: " + line);
                                   if ( line == null ) {
                                        break;
                                   }
                                   pw.println("loaclhost: " + line);
                                   pw.flush();
                               }
                               pw.flush();
                           } else {
                               pw.println("invalid method");
                               pw.flush();
                           }
                           pw.close();
                           s.close();
                        }
                        //se.close();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }
}

Beispiel: einfacher Web Client

import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class WebClient {

   public static void main(String[] args) {
       try {
           //Socket s = new Socket("www.dhbw-mannheim.de",80);
           Socket s = new Socket("localhost",8080);
           System.out.println("connected to " + s);
           PrintWriter pw = new PrintWriter(s.getOutputStream());
           BufferedReader br = new BufferedReader(
                           new InputStreamReader( s.getInputStream() ) );
           // http version 0.9:
           pw.println("GET /index.html HTTP/1.0");
           //pw.println("GET /piwik/piwik.php");
           //pw.println("GET /typo3temp/stylesheet_ef2d27d571.css");
           pw.flush();
          
           PrintWriter datei = new PrintWriter(
                                     new FileWriter("geholt.html"));
           System.out.println("calling client readline ...");
           while ( true ) {
               String zeile = br.readLine();
               System.out.println("empfangen: " + zeile);
               if ( zeile == null ) {
                   break;
               }
               //if ( ! zeile.contains("src") ) { 
               // img/link src, a href, form action
               //  continue;
               //}
               datei.println(zeile);
               datei.flush();
           }
           datei.close();
           System.out.println("done");
           pw.close();
           br.close();
           s.close();
       } catch (UnknownHostException e) {
                   e.printStackTrace();
       } catch (IOException e) {
                   e.printStackTrace();
       }
   }
}

Aufgaben:

Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.

  1. Entwickeln Sie einen Web Client, der URLs aus den HTML Elementen src, href oder action extrahiert und in eine Datei schreibt.

  2. Verbessern Sie den Web Server, so dass dieser sicher gegen Hacking durch Directory Traversal wird. Führen Sie dazu ein sogennantes Document-Root Verzeichnis ein, und limitieren Sie die Zugriffe auf Dateien in diesem Verzeichnis.


Beispiel: Sockets, die auch Objekte transportieren können.

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class ObjectSocket {

    Socket s;
    ObjectOutputStream os;
    ObjectInputStream is;

    public ObjectSocket(Socket s) throws IOException {
        this.s = s;
        os = new ObjectOutputStream( s.getOutputStream() );
        is = new ObjectInputStream( s.getInputStream() );
    }

    public void send(Object o) throws IOException {
        os.writeObject(o); // besser synchronized(os)
        os.flush();
    }

    public Object receive() throws IOException, ClassNotFoundException {
        return is.readObject(); // besser synchronized(is)
    }

    public void close() throws IOException {
        os.close();
        is.close();
        s.close();
    }
}

Beispiel: Ein Server, der beliebige Runnable Klassen ausführen kann.

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class ExecServer {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
                ServerSocket se = new ServerSocket(1337);       
                while (true) {
                        System.out.println("waiting for connection...");
                        Socket s = se.accept();
                        System.out.println("connection from " + s);
                        ObjectSocket os = new ObjectSocket(s);
                        Runnable r = (Runnable)os.receive();
                        r.run(); // rechnen 
                        os.send(r);
                        os.close();
                }
                 
        }
}

Beispiel: Interface für multipy() Methode.

public interface MMInf {
     public void multiply(double[][] C, double[][] A, double[][] B);
}

Beispiel: Verteilte Matrix-Multiplikation (noch nicht fertig).

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class DistMult /*implements MMInf*/ {

        int anzahl;
        String[] partners;

        public DistMult(String[] partners) { // host-names
                this.partners = partners;
                anzahl = partners.length;
        }

        public void multiply(double[][] C, double[][] A, double[][] B) throws UnknownHostException, IOException, ClassNotFoundException {
          RunMatrix[] proc = new RunMatrix[anzahl];
          ObjectSocket[] link = new ObjectSocket[anzahl];
          for ( int i = 0; i < anzahl; i++ ) {
                  proc[i] = new RunMatrix(C,A,B,anzahl,i);
                  link[i] = new ObjectSocket( new Socket(partners[i],1337) );
                  link[i].send( proc[i] );
          }
          for ( int i = 0; i < anzahl; i++ ) {
                  RunMatrix rm = (RunMatrix)link[i].receive();
                  int m = rm.i;
                  proc[m] = rm;
          }
          // Matrix C zusammenfassen
          // Das Programm ist hier nicht fertig!
      }
}

//wird übers Netz verschickt und in ExecServer ausgeführt:
class RunMatrix implements Runnable { 

    double[][] C, A, B;
    int anzahl;
    int i;

    public RunMatrix(double[][] C, double[][] A, double[][] B,
                         int anzahl, int i) {
        this.C = C; // später optimieren, damit nicht soviel
        this.A = A; // Daten übers Netz versendet werden
        this.B = B;
        this.anzahl = anzahl;
        this.i = i;
    }

    public void run() { // aus RowMultProc
        int schritte = A.length / anzahl;
        if ( A.length % schritte != 0 ) {
             schritte++;
        }
        for ( int ii = i*schritte; 
              ii < Math.min((i+1)*schritte,A.length); 
              ii++ ) {
              for ( int j = 0; j < B[0].length; j++ ) {
                   double c = 0.0;
                   for (int k = 0; k < B.length; k++ ) {
                        c += A[ii][k] * B[k][j];
                   }
              C[ii][j] = c;
              }       
        }               
    }
}

Beispiel: Verwendung von DistMult.

Vorsicht: funktioniert nur für einen Partner! DistMult muss für mehrere Partner noch angepasst werden.

import java.io.IOException;
import java.net.UnknownHostException;

public class MatMultDist {

    public static double[][] randomMat(int n){
        double[][] mat = new double[n][n];
        for ( int i = 0; i < n; i++ ) {
                for ( int j = 0; j < n; j++ ) {
                        mat[i][j] = Math.random();
                }
        }
        return mat;
    }

    public static double[][] zeroMat(int n){
        double[][] mat = new double[n][n];
        for ( int i = 0; i < n; i++ ) {
                for ( int j = 0; j < n; j++ ) {
                        mat[i][j] = 0.0;
                }
        }
        return mat;
    }

    public static double[][] oneMat(int n){
        double[][] mat = new double[n][n];
        for ( int i = 0; i < n; i++ ) {
                for ( int j = 0; j < n; j++ ) {
                    if ( i == j ) {
                        mat[i][j] = 1.0;
                    } else {
                        mat[i][j] = 0.0;
                    }
                }
        }
        return mat;
    }

    public static void printMat(double[][] mat){
        for ( int i = 0; i < mat.length; i++ ) {
                for ( int j = 0; j < mat[0].length; j++ ) {
                    System.out.print(mat[i][j]);
                    if ( j < mat[0].length-1 ) {
                        System.out.print(", ");
                    }
                }
                System.out.println();
        }
        System.out.println();
    }

    public static boolean equalMat(double[][] A, double[][] B ){
        double eps = Double.MIN_VALUE*10.0;
        for ( int i = 0; i < A.length; i++ ) {
             for ( int j = 0; j < A[0].length; j++ ) {
                  double b = Math.abs(A[i][j]-B[i][j]);
                  if ( b >= eps) {
                          return false;
                  }
             }
        }
        return true;
    }

    public static void main(String[] args) {
        int n = 1000;
        double[][] C = zeroMat(n);
        double[][] A = randomMat(n);
        double[][] B = randomMat(n);
        double[][] Cp = zeroMat(n);
        double[][] Cpp = zeroMat(n);
                
        //SeqMult sm = new SeqMult();
        //ParMult pm = new ParMult();
        //ParProcMult pmp = new ParProcMult(100);
        String[] partner = new String[] { "localhost" }; 
        // new String[1]; partner[0] = "localhost";
        DistMult dm = new DistMult(partner); // funktioniert noch nicht für mehrere Partner!
                
        System.out.println("Matrix A = ");
        //printMat(A);
        System.out.println("Matrix B = ");
        //printMat(B);
                
        long sstart = System.currentTimeMillis();
        //sm.multiply(C,A,B);
        long sstop = System.currentTimeMillis();
                
        long pstart = System.currentTimeMillis();
        try {
            dm.multiply(Cp,A,B);
        } catch(UnknownHostException e) {
                e.printStackTrace();
        } catch(IOException e) {
                e.printStackTrace();
        } catch(ClassNotFoundException e) {
                e.printStackTrace();
        }
        long pstop = System.currentTimeMillis();
        System.out.println("Matrix C = ");
                
        long ppstart = System.currentTimeMillis();
        //pmp.multiply(Cpp,A,B);
        long ppstop = System.currentTimeMillis();
        System.out.println("Matrix C = ");
                
        //printMat(C);          
        System.out.println("seq      Zeit = " + (sstop-sstart));
        System.out.println("par      Zeit = " + (pstop-pstart));
        System.out.println("par proc Zeit = " + (ppstop-ppstart));
        System.out.println("gleich = " + equalMat(Cp,C));
        System.out.println("gleich = " + equalMat(Cpp,C));
        //System.out.println("eps = " + Double.MIN_VALUE);
        System.out.println("Anzahl CPUs = " + Runtime.getRuntime().availableProcessors());
    }
}

Aufgaben:

Es folgen einige weitere Ideen für Programmier-Aufgaben und Projekte.

  1. Fügen Sie die Klasse DistMult zu dem Matrix-Benchmark Programm hinzu und bringen Sie es zum Laufen. Vergleichen Sie die Performance dieser Klasse mit der Performance der sequentiellen und parallelen Implementierungen der Multiplikationsalgorithmen. Vervollständigen Sie das Programm, so dass es mindestens für 2 Partner funktioniert.

Die Bonus-Aufgaben müssen bis zum Samstag, dem 18. Juli 2009 bei mir per Email abgegeben sein, damit sie für die Klausur gezählt werden. kredel [at] rz.uni-mannheim.de
Alle Programme und sonstige Dateien (wie die HTML-Datei) müssen in einem ZIP-Archiv als Anhang in der Email enthalten sein. Für die vollständige und richtige Bearbeitung der Bonus-Aufgaben erhalten Sie 23 Punkte .