Lösungen

Werbung
Übungen zu „Objektorientierte Programmierung in Java“
PD Dr. Wolfgang Goerigk
Sommersemester 2009
Musterlösungen
Serie 3
Aufgabe 3.1 (Laboraufgabe, CSV-Ein- und Ausgabe)
Eine häufig wiederkehrende Aufgabe ist das Einlesen von sog. „comma separated values“ (.csv), wie sie
beispielsweise von Spreadsheet-Programmen (Excel o.ä.), von Kalender-Programmen oder auch aus
Datenbanken exportiert werden können. Diese Dateien haben i.a. die folgende Form:
Nettobetrag;Mehrwertsteuersatz;Bruttobetrag;Waehrung
1000,75;19;;€
2000,00;7;;$
3000,00;19;;Euro
Der Separator ist im deutschsprachigen Umfeld häufig ";" statt ",", weil "," in Fließkommazahlen verwendet
wird. Pro Zeile müssen nicht alle Felder belegt sein (z.B. ist das Bruttobetrag-Feld in dem o.a. Beispiel leer),
aber die Anzahl der Felder ist immer gleich. Manche Felder enthalten Zahlen (z.B. Nettobetrag (double) und
Mehrwertsteuersatz (int) im o.a. Beispiel), manche Zeichenreihen (z.B. „€“ oder „Euro“ im Feld Waehrung
des o.a. Beispiels). Im csv-Format ist die Kopfzeile nicht obligatorisch. Sie dient aber zur Benennung der
Spalten, aber auch als auch als Muster für die Anzahl der Spalten. Die erste Datenzeile ist also i.a. die zweite
Zeile der Datei.
Schreiben Sie ein Programm, das die Datei „Mehrwertsteuer.csv“ (s.o.) und in der gleichen Form auf die
Standardausgabe wieder ausgibt, allerdings zusätzlich mit berechnetem Bruttobetrag, also in der Form
Nettobetrag;Mehrwertsteuersatz;Bruttobetrag;Waehrung
1000,75;19; 1190,89;€
2000,00;7; 2140,00;$
3000,00;19; 3570,00;Euro
Hinweise:
1. Benutzen Sie die Klasse java.util.Scanner zweimal:
o Einmal mit dem Argument new File("Mehrwertsteuer.csv"), um den Dateiinhalt
zeilenweise einzulesen und
o einmal mit der jeweils eingelesenen Zeile als String-Argument, um die einzelnen Datensätze
zu separieren. Die Methode Scanner useDelimiter (String pattern) liefert
zu einem Scanner einen neuen, der die in pattern enthaltene Zeichenreihe, z.B. ";", als
Separator verwendet.
2. Die Klasse java.text.DecimalFormat können Sie verwenden, um den berechneten
Bruttowert wiederum in einer lokalisierten (deutschen) Form mit "," als Dezimalpunkt und z.B.
zwei Nachkommastellen auszugeben. Die Zeile
s = new DecimalFormat("0.00").format(x);
liefert zur Zahl x einen solchen String in s.
Lösung:
package Serie_3;
import
import
import
import
import
java.io.File;
java.io.FileNotFoundException;
java.io.PrintStream;
java.util.Scanner;
java.text.*;
public class Aufgabe_3_1 {
public static void main(String[] args) throws FileNotFoundException {
Scanner scanner =
new Scanner(new File("Mehrwertsteuer.csv")).useDelimiter(";");
String header = scanner.nextLine();
String line;
double netto, brutto;
int mwst;
String brutto_string, waehrung;
// ----------------------------------------------// Zeilenweises Einlesen und Verarbeiten der Datei
// "Mehrwertsteuer.csv"
// -------------------while (scanner.hasNextLine()) {
Scanner sc =
new Scanner(scanner.nextLine()).useDelimiter(";");
netto = sc.nextDouble();
mwst = sc.nextInt();
sc.next();
waehrung = sc.next();
brutto = netto + netto * mwst / 100.0;
brutto_string = new DecimalFormat("0.00").format(brutto);
System.out.println
(netto + ";" + mwst + ";" + ";"
+ brutto_string + ";" + waehrung);
}
}
}
Bei dieser Aufgabe sind vor allem zwei Dinge wichtig:
1. Wechsel des Eingabemediums: Statt von der Kommandozeile oder der Standard-Eingabe (Konsole)
lesen wir die Eingabedaten jetzt aus einer Datei. Die eigentliche Berechnung bleibt davon i.W.
unberührt.
2. Mit Schleifen können wir die Eingabedatei zeilenweise einlesen, verarbeiten und zeilenweise
wieder ausgeben. Für die Unabhängigkeit von der Länge der Eingabedatei (der Anzahl der Zeilen) ist
die while-Schleife wichtig: Solange noch eine Zeile vorhanden ist, lies sie, verarbeite die Daten und
gebe die Resultate aus.
Aufgabe 3.2 (Laboraufgabe, CSV-Ausgabe)
Ergänzen Sie Ihr Programm aus Aufgabe 3.1 so, dass es die Ausgabe zusätzlich in eine Textdatei (z.B.
„Ergebnis.csv“) ausgibt. Fügen Sie dabei sowohl in der Kopfzeile als auch in den Datenzeilen zwischen den
Feldern "Mehrwertsteuersatz" und "Bruttobetrag" eine neue Spalte "Mehrwertsteuer"
ein, die in den Datenzeilen die berechnete Mehrwertsteuer enthält.
Zur Probe können Sie die entstehende Datei beispielsweise in Excel oder OpenOffice Calc einlesen.
Lösung:
package Serie_3;
import
import
import
import
import
java.io.File;
java.io.FileNotFoundException;
java.io.PrintStream;
java.util.Scanner;
java.text.*;
public class Aufgabe_3_2 {
public static void main(String[] args) throws FileNotFoundException {
Scanner scanner =
new Scanner(new File("Mehrwertsteuer.csv")).useDelimiter(";");
PrintStream output = new PrintStream("Ergebnis1.csv");
// ----------------------------------// Ausgabe der Kopfzeile der csv-Datei
// ----------------------------------String header = scanner.nextLine();
String n = "Nettobetrag", m1 = "Mehrwertsteuersatz",
m2 = "Mehrwertsteuer",
b = "Bruttobetrag", w = "Waehrung",
sep = ";";
header = n+sep+m1+sep+m2+sep+b+sep+w;
output.println(header);
double netto, brutto, steuer;
int mwst;
String brutto_string, waehrung, steuer_string;
// ----------------------------------------------// Zeilenweises Einlesen und Verarbeiten der Datei
// "Mehrwertsteuer.csv"
// -------------------while (scanner.hasNextLine()) {
Scanner sc =
new scanner(scanner.nextLine()).useDelimiter(";");
netto = sc.nextDouble();
mwst = sc.nextInt();
sc.next();
waehrung = sc.next();
brutto = netto + netto * mwst / 100.0;
brutto_string = new DecimalFormat("0.00").format(brutto);
steuer = netto * mwst / 100.0;
steuer_string = new DecimalFormat("0.00").format(steuer);
output.println
(netto + ";" + mwst + ";" + steuer + ";"
+ brutto + ";" + waehrung);
}
}
}
Bei dieser Aufgabe passiert sichts weiter als ein Wechsel des Ausgabemediums. Statt auf die
Standardausgabe schreiben wir nun die Resultate in eine Datei, d.h auf einen PrintStream.
Aufgabe 3.3 (Laboraufgabe, CSV-Ausgabe)
Berechnen Sie Mehrwertsteuer und Bruttobetrag für alle Nettobeträge zwischen 0,- € und 30.000,- € im
Abstand 1.000,- €, d.h. für die Nettobeträge 0,- €, 1000 €, 2000 € usw. Geben Sie die zugehörigen Daten
analog Aufgabe 3.2 in eine csv-Datei aus.
Zusatz (freiwillig):
Versuchen Sie, die Daten so in eine csv-Datei zu schreiben, dass Sie diese mit Excel oder OpenOffice Calc
einlesen und in einem Diagramm hübsch darstellen können.
Lösung:
package Serie_3;
import
import
import
import
java.io.File;
java.io.FileNotFoundException;
java.io.PrintStream;
java.text.*;
public class Aufgabe_3_3 {
public static void main(String[] args) throws FileNotFoundException {
PrintStream output = new PrintStream("Ergebnis2.csv");
// ----------------------------------// Ausgabe der Kopfzeile der csv-Datei
// ----------------------------------String n = "Nettobetrag", m1 = "Mehrwertsteuersatz",
m2 = "Mehrwertsteuer",
b = "Bruttobetrag", w = "Waehrung", sep = ";";
String header = n+sep+m1+sep+m2+sep+b+sep+w;
output.println(header);
double netto, brutto, steuer;
int mwst = 19;
String brutto_string, steuer_string;
// -----------------------------------------// Ausgabe fuer 0,-, 1000,-, ..., 30.000,-- €
// in die Datei Ergebnis2.csv
// -------------------------for (netto = 0; netto <= 30000.0; netto = netto + 1000.0) {
brutto = netto + netto * mwst / 100.0;
brutto_string = new DecimalFormat("0.00").format(brutto);
steuer = netto * mwst / 100.0;
steuer_string = new DecimalFormat("0.00").format(steuer);
output.println
(netto + ";" + mwst + ";" + steuer_string + ";"
+ brutto_string + ";" + "€");
}
}
}
Aufgabe 3.4 (Laboraufgabe, Komplexere csv-Dateien)
Auf der Vorlesungs-Webseite finden Sie eine Datei "Bankauszuege.csv". So oder so ähnlich liefert
Ihnen Ihre Bank oder Sparkasse die Übersicht über die laufenden Kontobewegungen z.B. eines Girokontos,
wenn Sie z.B. im Electronic Banking einen csv-Export der Kontobewegungen eines bestimmten Zeitraumes
abfordern. Neben Buchungsdatum, Valuta, Informationen über Empfänger und Verwendungszweck usw.
stehen im Feld "Betrag" die Zugänge als positive, die Abgänge als negative Zahlen.
Die Kontobewegungen werden durch eine Zeile ohne Daten abgeschlossen, gefolgt von einer Zeile, die den
alten Saldo wiedergibt:
;;;;;;;;;
alter Saldo;15.12.2009;1534,77;EUR;;;;;;
1. Lesen Sie diese Datei ein, summieren Sie die einzelnen Zu- und Abgänge und berechnen Sie den
neuen Saldo.
2. Berechnen Sie ebenfalls, wie hoch die Summe aller im Feld "Verwendungszweck 1" als
"UEBERWEISUNG" gekennzeichneten Abgänge ist.
Hinweise:
Mit dieser Aufgabe sollten Sie sich vor dem nächsten Labor (08.05.2009) beschäftigen, weil Sie sie während
des Labors nicht vollständig bearbeiten können.
Für eine Zeichenreihe (String) s1 kann die Methode Boolean equals (String s2) aufgerufen
werden, die s1 mit s2 zeichenweise vergleicht.
Lösung:
package Serie_3;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.text.*;
public class Aufgabe_3_3 {
public static void main(String[] args) throws FileNotFoundException {
Scanner scanner = new Scanner(new File("Bankauszuege.csv"))
.useDelimiter(";");
scanner.nextLine(); // Ueberlese die Kopfzeile
//-------------------------------------// Die csv-Datei enthaelt die 10 Spalten
//
// buchungsdatum (Datum)
// valuta (Datum)
// betrag (double)
// waehrung (String)
// empf1 (String)
// empf2 (String)
// primanota (String)
// blzempf (String)
// ktoempf (String)
// zweck (String)
//
// -------------double betrag;
String zweck;
double sum_betrag = 0.0, sum_ueb = 0.0;
// --------------------------------------------// Lese und verarbeite die csv-Datei zeilenweise
// --------------------------------------------while (scanner.hasNextLine()) {
Scanner sc =
new Scanner(scanner.nextLine()).useDelimiter(";");
//
//
//
//
if
---------------------------------------------------Beende die Schleife, falls die eingelesene Zeile die
Zeile ";;;;;;;;;" ist (buchungsdatum = "")
------------------------------------------(sc.next().equals("")) // buchungsdatum
break;
sc.next(); // valuta
betrag = sc.nextDouble();
sum_betrag = sum_betrag + betrag;
sc.next(); // waehrung
sc.next(); // empf1
sc.next(); // empf2
sc.next(); // primanota
sc.next(); // blzempf
sc.next(); // ktoempf
zweck = sc.next();
if (zweck.equals("UEBERWEISUNG")) {
sum_ueb = sum_ueb + betrag;
}
//String sum = new DecimalFormat("0.00").format(sum_betrag);
}
// ----------------------------------------------------------// Einlesen der letzten Zeile. In der dritten Spalte steht der
// alte Saldo
// ---------Scanner sc = new Scanner(scanner.nextLine()).useDelimiter(";");
sc.next();
sc.next();
double saldo = sc.nextDouble();
// ----------------------// Vorbereiten der Ausgabe
// ----------------------String oldSaldo = new DecimalFormat("0.00").format(saldo);
String sumBetrag = new DecimalFormat("0.00").format(sum_betrag);
String newSaldo =
new DecimalFormat("0.00").format(sum_betrag + saldo);
String ueberw = new DecimalFormat("0.00").format(sum_ueb);
// ------// Ausgabe
// ------System.out.println("Alter
System.out.println("Summe
System.out.println("Neuer
System.out.println("Summe
Saldo: " + oldSaldo);
Bewegungen: " + sumBetrag);
Saldo: " + (newSaldo));
UEBERWEISUNGEN: " + ueberw);
}
}
Aufgabe 3.5 (Hausaufgabe, Guter und schlechter Programmierstil)
Gegeben sei das folgende Programm:
public class Test {public static void main(String[] args) {
Test t = new Test();
System.out.println(t.doSomething(1000));}
double doSomething(int schritte) {double pi=0.0;
10
for(double i=0,n=-1.0,z=1.0;i<schritte; n+=2,pi+=z/n,z*=-1,++i);
return pi*4;
}
}
Das Programm berechnet eine Näherung der Zahl π durch eine Zahlenreihe. Schreiben Sie das Programm so
um, dass auch Dritte verstehen können, was es eigentlich tut.
•
•
•
•
Korrigieren Sie das Textlayout des Programms (Zeilenumbrüche, Einrückung usw.).
Vergeben Sie aussagekräftige Namen für Variablen und Methoden.
Schreiben Sie die for-Schleife um, in dem Sie Zuweisungen, die im Schleifenkopf unnötig sind, in
den Schleifenrumpf verlagern.
Fügen Sie Kommentare ein.
Lösung:
package Serie_3;
public class Test {
// ---------------------------------------------------------------------// Hauptprogramm. Berechnet eine Naeherung für die Kreiszahl Pi mit einer
// Schrittzahl von 1000. Erhöhung der Schrittzahl erhöht die
// Genauigkeit der Naeherung
// -------------------------public static void main(String[] args) {
Test t = new Test();
System.out.println(t.berechne_pi(1000));
}
// ----------------------------------------------// Berechnung von Pi durch die alternierende Reihe
// Pi/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + 1/13 - 1/15 + 1/17 -...
//
// schritte = Anzahl der Iterationsschritte
// ---------------------------------------double berechne_pi(int schritte) {
double pi = 0.0;
double nenner = -1.0, zaehler = 1.0;
for (int i = 0; i < schritte; i++) {
nenner = nenner + 2;
pi = pi + zaehler / nenner;
zaehler = -zaehler;
}
return pi * 4;
}
}
Das Programm berechnet eine Näherung der Kreiszahl π mithilfe der alternierenden Reihe
Pi
/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + 1/13 - 1/15 + 1/17 -...
Aufgabe 3.6 (Hausaufgabe, Zahlen raten)
Das Spiel „Zahlen raten“ funktioniert so: Ein Spieler A (der Computer) denkt sich eine Zahl zwischen 0 und
einer bestimmten Obergrenze aus. Der Spieler B (Benutzer) muss nun versuchen, die Zahl zu erraten. Nach
jedem Versuch bekommt er dazu von A den Hinweis, ob seine geratene Zahl zu groß oder zu klein ist. Errät
er die Zahl richtig, endet das Spiel. Ein Dialog auf der Konsole könnte z.B. wie folgt aussehen:
Bitte geben Sie eine Zahl zwischen 1 und 100 ein:
35
Zahl zu klein. Bitte erneut versuchen:
75
Zahl zu gross. Bitte erneut versuchen:
50
Gewonnen. Sie haben 3 Versuche benötigt
Programmieren Sie das Spiel. Zu Beginn ermittelt das Programm eine zu ratende Zufallszahl zwischen 1 und
100, z.B. durch
int zufallsZahl = (int) (Math.random() * 100 + 1);
Die statische Methode java.lang.Math.random() liefert eine Zufallszahl zwischen im Intervall [0..1).
Im Erfolgsfall wird die Anzahl der Versuche ausgegeben. Wenn Sie Lust und Zeit haben, spielen Sie Ihr Spiel
solange, bis Sie die Zahl ebenfalls in höchstens drei Versuchen erfolgreich geraten haben.
Lösung:
package Serie_3;
import java.io.*;
import java.util.*;
public class Zahlenraten {
public static void main (String[] args) throws Exception {
// -----------------------------// Zufallszahl zwischen 1 und 100
// -----------------------------int zufallsZahl = (int) (Math.random() * 100 + 1);
int anzahlVersuche = 1;
Scanner input = new Scanner(System.in);
System.out.println("Rate eine Zahl zwischen 0 und 100:");
int eingabe = input.nextInt();
// ------------------------------------------------------// Lese solange int-Werte von der Standardeingabe, bis die
// eingegebene Zahl gleich der anfangs berechneten Zufallszahl ist.
// ---------------------------------------------------------------while (eingabe != zufallsZahl) {
anzahlVersuche++;
if (eingabe < zufallsZahl) {
System.out.println("Zahl zu klein. Nocheinmal:");
eingabe = input.nextInt();
}
else if(eingabe > zufallsZahl) {
System.out.println("Zahl zu groß. Nocheinmal:");
eingabe = input.nextInt();
}
}
System.out.println
("Erraten mit "+ anzahlVersuche +" Versuch(en)");
}
}
Herunterladen