# Objekt mit String und Int aus TxT Datei erstellen



## Typo_ex (19. Dez 2019)

Hi Leute,
ich arbeite gerade an einem Währungs-Rechner, der die Wechselkurse aus einer TxT-Datei lesen soll.
Die Liste wird wie folgt aussehen:

Euro, 1.29921
US Dollar, 1.399586
Australian Dollar, 1.445676

Ich möchte mit diesen Daten  Objekte erstellen und diese dann in ein Array speichern.
Jedoch stoße ich dort auf einige Probleme.

1. Die Textdatei auslesen
Dazu habe ich im Netz zwei Möglichkeiten gefunden:
-BufferedReader
-ein Scanner
jedoch hab ich keine Ahnung, wie ich die Daten in ein Objekt und ein Array speichere und den Syntax der beiden Möglichkeiten verstehe ich auch nicht ganz.(bzw. wie ich den Constructor anpeile)

2. Später soll es ein Eingabe-Feld geben. Wenn man dort z.B. "Dol" eingibt, sollen alle Währungen angezeigt werden, die "Dol" im Namen haben.
Habt ihr mir dafür einen Lösungsansatz? Ich habe an eine ArrayList gedacht, so dass alle Währungsnamen in dem Array geprüft werden. Aber auch da hab ich keine Ahnung von der Syntax und wie ich anfangen soll.

LG und frohe Feiertage
Typo


----------



## Xyz1 (19. Dez 2019)

Fail-Fast-Behavior:

```
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Objects;

public class Geld {
	private String name;
	private double wert;

	public Geld(String name, double wert) {
		super();
		this.name = name;
		this.wert = wert;
	}

	public boolean startsWith(String p) {
		return name.startsWith(p);
	}

	@Override
	public int hashCode() {
		return Objects.hash(name);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Geld other = (Geld) obj;
		return Objects.equals(name, other.name);
	}

	@Override
	public String toString() {
		return String.format("Geld [name=%s, wert=%s]", name, wert);
	}
}

class Leser {
	private ArrayList<Geld> list = new ArrayList<Geld>();

	public static void main(String[] args) throws IOException {
		Leser l = new Leser();
		try (BufferedReader r = new BufferedReader(new FileReader(""))) {
			a: while (true) {
				for (int i = 0; i < 3; i++) {
					String line = r.readLine();
					if (line != null && !line.isBlank()) {
						String[] b = line.split(", ");
						if (b.length == 2 && !b[0].isBlank()) {
							try {
								l.list.add(new Geld(b[0], Double.parseDouble(b[1])));
							} catch (NumberFormatException e) {
								break a;
							}
						} else {
							break a;
						}
					} else {
						break a;
					}
				}
			}
		}

		for (Geld geld : l.list) {
			if (geld.startsWith("US Dol")) {
				System.out.println(geld);
			}
		}
	}
	
}
```


und den inhalt der main-Methode müsstest Du noch in sinnvolle Methoden schreiben.


----------



## kneitzel (19. Dez 2019)

Ich will einmal versuchen, deine Fragen zu beantworten - den Code von Tobias würde ich erst einmal ignorieren.... break mit label ... )

BufferedReader hilft, etwas aus einer Quelle zu lesen. Eine Quelle kann vieles sein, z.B. eine Datei. Hier ist ein Standard-Vorgehen, dass sich hier anbietet, die Datei Zeile für Zeile zu lesen. Dazu hat ein BufferedReader die Methode readLine.
Diese Methode gibt entweder die nächste Zeile oder null zurück.

Da Du alle Zeilen lesen willst, gibt es dann oft ein Konstrukt wie:

```
String line;
try (BuffereReader reader = ....) {
    while ((line = reader.nextLine())!=null) {
        // line auswerten
    }
} catch (IOException ex) {
    // Exception auswerten / ausgeben
}
```
Hier hast du drei Dinge drin:
a) ein "try with resources" - dadurch ist sicher gestellt, dass am Ende der Reader auch geschlossen wird.
b) eine while schleife - in der Bedingung der while-Schleife wird line die nächste Zeile zugewiesen und dann wird geprüft, ob das erfolgreich war (also != null).
c) So ein Reader kann auch eine Exception werfen. Die wollen wir auffangen.

Nun hast Du eine Zeile, die so aussieht: <Text>, <zahl>. Hier würde ich immer mit einem regulären Ausdruck heran gehen. Aber da dies am Anfang schwer sein kann, machen wir es auf traditionelle Weise:
String.split kann einen String in mehrere aufspalten. Also ein
`String[] parts = line.split(",");`
sollte Dir den String aufteilen.
- Nun prüfen wir, ob wir wirklich 2 Teile haben: if (parts,length == 2)
- dann haben wir parts[0] den Namen und parts[1] die Zahl mit führenden Leerzeichen. Daraus können wir eine Zahl machen mit
`double value=Double.parseDouble(parts[1].trim());`
Der Aufruf trim() auf dem String löscht davor und danach sogenannte Whitespace weg, also Leerzeichen, Tabs und so ...

Nun bleibt nur noch die Frage nach dem Speichern und wo wir was hinein packen:
Dazu wäre die Objektorientierte Lösung, dass wir eine Klasse schreiben und die dann ausstatten. Eine solche Klasse siehst Du z.B. bei Tobias. Die kannst Du nehmen und dann evtl. das parsen dort mit aufnehmen.

Aber evtl. brauchst Du das auch nicht. Du hast ja nur eine Map von dem Namen zu einer Zahl. Also kannst Du auch einfach eine `HashMap<String,Double>` nutzen, die Du dann fütterst.

Wenn Du Du dann alle Elemente haben willst, die mit einer bestimmten Zeichenkette anfangen, dann kannst du - so wie es Tobias schon zeigt, startsWith nutzen. Bei einer HashMap würde man dazu alle Schlüssel (keyset nennt sich das) dann nutzen.

Das wäre dann die Erklärung, wie ich das am Anfang machen würde. Code liefere ich in wenigen Minuten nach.


----------



## kneitzel (19. Dez 2019)

Also ohne die Objektorientierung wäre das dann ungefähr sowas:

```
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;

public class Currency {

    public static Map<String, Double> readCurrencies(final String filename) {
        Map<String, Double> result = new HashMap<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String line;
            while ((line = reader.readLine()) != null) {
                // ignore empty lines.
                if (line.trim().isEmpty()) continue;

                String parts[] = line.split(",");
                if (parts.length != 2) {
                    System.out.println("Unable to parse line: " + line);
                    continue;
                }

                result.put(parts[0], Double.parseDouble(parts[1].trim()));
            }
        } catch (FileNotFoundException e) {
            System.err.println("File " + filename + " not found: " + e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("Error reading File " + filename + ": " + e.getMessage());
            e.printStackTrace();
        }

        return result;
    }

    public static List<String> filterKeys(Map<String, Double> currencies, String filterText) {
        List<String> result = new ArrayList<String>();
        for (String name: currencies.keySet()) {
            if (name.startsWith(filterText)) result.add(name);
        }

        return result;
    }

    public static void main(String[] args) {
        Map<String, Double> currencies = readCurrencies("currencies.txt");
        List<String> filteredNames = filterKeys(currencies, "US");
        for (String filteredName: filteredNames) {
            System.out.println(filteredName);
        }
    }
}
```


----------



## kneitzel (19. Dez 2019)

Und dann auch noch einmal, wie eine einfache Version mit einer Klasse Currency aussehen könnte:

```
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Currency {

    private String name;
    private double value;

    public Currency(final String name, final double value) {
        this.name = name;
        this.value = value;
    }

    public static Currency parseCurrency(String line) {
        String parts[] = line.split(",");
        if (parts.length != 2) throw new IllegalArgumentException("String not in format <name>, <value>!");
        return new Currency(parts[0], Double.parseDouble(parts[1].trim()));
    }

    public static List<Currency> readCurrencies(final String filename) {
        List<Currency> result = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String line;
            while ((line = reader.readLine()) != null) {
                // ignore empty lines.
                if (line.trim().isEmpty()) continue;

                try {
                    result.add(Currency.parseCurrency(line));
                } catch (IllegalArgumentException ex) {
                    System.out.println("Unable to parse line: " + line);
                }
            }
        } catch (FileNotFoundException e) {
            System.err.println("File " + filename + " not found: " + e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("Error reading File " + filename + ": " + e.getMessage());
            e.printStackTrace();
        }

        return result;
    }

    public boolean nameStartWith(final String filterText) {
        return name.startsWith(filterText);
    }

    @Override
    public String toString() {
        return "(" + name + ": " + value + ")";
    }

    public static void main(String[] args) {
        List<Currency> currencies = readCurrencies("currencies.txt");
        for (Currency currency: currencies) {
            if (currency.nameStartWith("US"))
                System.out.println(currency);
        }
    }
}
```


----------



## Xyz1 (19. Dez 2019)

JustNobody hat gesagt.:


> den Code von Tobias würde ich erst einmal ignorieren.... break mit label


Hatten wir das nicht schon? Etwas weniger Meinung wäre schön.


----------



## kneitzel (19. Dez 2019)

Tobias-nrw hat gesagt.:


> Hatten wir das nicht schon? Etwas weniger Meinung wäre schön.


Nein. Sowas hatten wir noch nicht. Du hast schon viel Müll gepostet (Unvergessen ist die eine Stream Lösung von Dir, die Du als Beste Lösung überhaupt verteidigt hast....), aber das ist wirklich ein neues Highlight.

Aber zu der Bewertung dieses Threads-
Meiner Meinung nach ist es ein Unding, einem offensichtlichen Anfänger auf Fragen einfach nur Code hin zu klatschen. Aber sei es drum. Wenn es dann aber so ein Code ist wie Du da in main geschrieben hast, dann ist es schon recht extrem.

Vor allem: Du hast doch schon eine Klasse Geld gemacht. Wieso packst Du da nicht Teile rein? Da gehört es doch logisch hin. Oder spätestens beim Einführen eines Labels sollte selbst einem mittelmäßigen Programmierer klar sein: Ich mache wenigstens eine Methode ... (Das ist wirklich sowas von 08/15).

Aber ja: Das ist nur meine Meinung. Du darfst gerne eine andere Meinung haben. Von mir aus kannst Du deinen Code als Clean Code ansehen, als den Heiligen Gral, als was auch immer. Das interessiert mich nun wirklich nicht mehr. Eine Diskussion werde ich auch nicht mit Dir darüber führen.


----------



## Xyz1 (19. Dez 2019)

Etwas weniger geistigen Bullshit wäre schön...


----------



## thecain (19. Dez 2019)

aber über break mit label sollte man schon nicht mehr Diskussionen führen müssen...


----------



## Xyz1 (20. Dez 2019)

thecain hat gesagt.:


> aber über break mit label sollte man schon nicht mehr Diskussionen führen müssen...


Das ist richtig, aber ich habe dazu geschrieben,


Tobias-nrw hat gesagt.:


> und den inhalt der main-Methode müsstest Du noch in sinnvolle Methoden schreiben


dann lösen sich diese break mit names auf.

und naja... auch richtig, ich werde nicht mehr mit Code antworten, wenn dieser nicht verstanden werden kann.


----------



## mihe7 (20. Dez 2019)

thecain hat gesagt.:


> aber über break mit label sollte man schon nicht mehr Diskussionen führen müssen...


Wobei...


----------



## Typo_ex (20. Dez 2019)

Danke für eure schnellen Antworten. Ja, ich bin noch ein Anfänger und mir fällt es schwer beide Codes zu lesen. Die Erklärung von dir @JustNobody war gut, jetzt weiß ich zumindest im groben wie es funktioniert. Ich glaube mit dem Klassen-Code kann ich etwas anfangen, ich muss das gleich mal testen


----------



## Typo_ex (20. Dez 2019)

@JustNobody was genau hab ich am Ende? einzelne Arrays mit einem String und int oder einen Array mit verschiedenen strings und int? Danke, der Code ist super. Ich habe ein paar Werte geändert und es läuft schon! Jetzt muss ich das noch mit einem Scanner verknüpfen


----------



## kneitzel (20. Dez 2019)

Wenn ich das richtig sehe, willst du den Namen des Parameters ändern. Der bleibt aber so, wie er ist. Parameter sind wie Kartons, in die Du etwas rein tun willst.

Was benötigt wird ist dann bei diesem Bild, dass Du in den Karton etwas rein tust. Bei Methoden passiert dies beim Aufruf:

```
readCurrencies("currencies.txt");
```
Das war beim ersten Code von mir. Die Methode readCurrencies erwartete einen Parameter und da habe ich den String „currencies.txt“ übergeben. Da beim Aufruf kannst du also in doppelten Anführungszeichen den Pfad mit Dateiname angeben. (Falls Du \ verwenden willst: die haben eine besondere Bedeutung, daher musst du die doppelt schreiben. Damit kann man besondere Zeichen angeben, z.B. einen Zeilenumbruch \n oder ein Tab \t. Und das Zeichen selbst ist \\.


----------



## Typo_ex (20. Dez 2019)

@JustNobody ok, das hab ich hinbekommen (deshalb habe ich gerade auch vor 5 Minuten den Text bearbeitet)
was genau hab ich am Ende? einzelne Arrays mit einem String und int oder einen Array mit verschiedenen strings und int?


----------



## kneitzel (20. Dez 2019)

Weder noch. Diese Anforderung, dass Du Objekte in einem Array haben willst, wurde so nicht umgesetzt. Das Problem an Arrays ist, dass Du die Größe wissen musst, denn sie haben eine konstante Größe. Aus dem Grund wird in so Fällen meist ein Datentyp aus dem Java Framework verwendet.

Das erste Beispiel speichert die Elemente z.B. in einer (Hash)Map. Eine Map speichert Paare aus Key, Value und bietet gute Suchmöglichkeiten nach Keys.
Das zweite Beispiel erzeugt eine List aus Instanzen der erstellten Klasse.

Wenn es ein Array sein muss, dann musst Du Dir diese Methode aus dem zweiten Beispiel im Detail ansehen und auf Arrays umstellen:

```
public static List<Currency> readCurrencies(final String filename) {
        List<Currency> result = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            String line;
            while ((line = reader.readLine()) != null) {
                // ignore empty lines.
                if (line.trim().isEmpty()) continue;

                try {
                    result.add(Currency.parseCurrency(line));
                } catch (IllegalArgumentException ex) {
                    System.out.println("Unable to parse line: " + line);
                }
            }
        } catch (FileNotFoundException e) {
            System.err.println("File " + filename + " not found: " + e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("Error reading File " + filename + ": " + e.getMessage());
            e.printStackTrace();
        }

        return result;
    }
```

Also statt List<Currency> muss Currency[] zurück gegeben werden und dann musst keine ArrayList erstellt werden sondern das Array. Und wie füllst Du dann das Array?

(Wenn die Nutzung der Java Framework Klassen ausgeschlossen ist, dann handelt es sich um eine Aufgabe in der Schule oder Studium, daher gebe ich da jetzt nichts mehr vor sondern versuche Dich zu leiten, damit Du es selbst erarbeitest. Das müsste dann besser sein, als die Vorgabe einer Lösung. Ich erwähne das nur kurz, da Du ja direkt mit "Code zugeschmissen" wurdest und das jetzt plötzlich nicht mehr ganz so ist. Du hast nichts falsch gemacht und alles ist ok - nur die Zielsetzung von mir hat sich geändert in der Hoffnung, Dir den maximalen Lernerfolg zu geben.)


----------



## Typo_ex (20. Dez 2019)

@JustNobody kein Problem, du hast mir gut geholfen. Als nächstes werde ich mich mit Maps befassen, ich glaube dass die Lösung passend ist. Da fehlt noch einiges an Code, nur auf die Reader-Lösung wäre ich in 100 Jahren nicht gekommen, da mir dazu einfach noch die praktische Erfahrung fehlt


----------



## kneitzel (20. Dez 2019)

Typo_ex hat gesagt.:


> @JustNobody kein Problem, du hast mir gut geholfen. Als nächstes werde ich mich mit Maps befassen, ich glaube dass die Lösung passend ist. Da fehlt noch einiges an Code, nur auf die Reader-Lösung wäre ich in 100 Jahren nicht gekommen, da mir dazu einfach noch die praktische Erfahrung fehlt


Ahh, ok. Also war Array nur ein Ansatz und nicht gefordert.

Ja, beschäftige Dich etwas mit den Collections von Java. Also Map, List und Set. Die konkreten Implementierungen sind ggf. nicht ganz so wichtig, wenn es nur um die Anwendung geht. Dann nutzt man z.B. einfach die HashMap und ArrayList.

Übersichtsseiten, die Du Dir vielleicht ansehen möchtest:
- https://www.java-tutorial.org/collections.html
- http://www.scalingbits.com/java/javakurs2/programmieren2/collection/ueberblick

Und bei Fragen: Immer raus damit. Wir helfen gerne!


----------



## Xyz1 (20. Dez 2019)

Typo_ex hat gesagt.:


> ich glaube dass die Lösung passend ist


@Typo_ex Wenn du es gleich richtig machen willst, nimm einfach meins, und lass dich nicht durch Abwegigkeiten die durch ein gekränktes Ego entstanden sind beirren. Bitte beachte dabei aber sinnvolle Methoden hinzuzufügen.
@JustNobody Ich habe mich deiner Ausdrucksweise angepasst.


----------



## kneitzel (20. Dez 2019)

Tobias-nrw hat gesagt.:


> @Typo_ex Wenn du es gleich richtig machen willst, nimm einfach meins, und lass dich nicht durch Abwegigkeiten die durch ein gekränktes Ego entstanden sind beirren. Bitte beachte dabei aber sinnvolle Methoden hinzuzufügen.
> @JustNobody Ich habe mich deiner Ausdrucksweise angepasst.


Ich habe keine Probleme mit Deiner Meinung.  Die darfst Du gerne zeigen, sagen und Dich damit auch gerne so lächerlich machen, wie Du willst. So wie allen Anfängern hier hast Du auch das Recht, hier zu schreiben, was Du willst. Und sowas muss Dir auch nicht peinlich sein. (Dieses total darauf bestehen, dass der verzapfte Quatsch eine tolle oder die Beste Lösung ist, wäre mir aber peinlich ... aber das ist halt auch nur meine Sicht/Meinung....)

Und ich bin sicher, dass @Typo_ex sich auch bestimmt seine Meinung gebildet haben wird. Und Deine Antwort jetzt ist mir ehrlich gesagt auch etwas unverständlich: in #17 hat der TE doch bereits klar gemacht, dass ihm bei diesem Thema soweit geholfen wurde und dass er sich nun etwas den Maps zuwenden möchte ... Wieso sollte er das, was er begriffen hat, wieder über Board werfen um sich mit Deinem Code auseinander zu setzen?

Aber ok: Da Du darauf großen Wert legst, dann mache ich einmal ein kleines Code Review - Ich helfe Anfängern gerne und ich sehe keinen Grund, warum man einem Anfänger wie Dir nicht auch helfen sollte:

Also einmal zum objektorientierten Aufbau:
- Wenn man Code zum parsen von Werten hat, dann gehören die zu der Klasse. Beispiele im Framework wären da also sowas wie Integer.parseInt, Double.parseDouble, ... Somit wäre dies eine Funktionalität, die in deine Klasse Geld gehören würde. Hätte dann auch direkt zur Folge, dass man dann die massive Verschachtelungstiefe reduziert hätte.

Generelle Auffälligkeiten:
- Label sind in Java immer ein Zeichen, dass der Code falsch strukturiert wurde. (Das auszuführen spare ich mir. Google gibt da genug. Oder frag bei SO oder SE nach. Da die da ja alles mehr wissen als wir alle zusammen  )
- catch ohne Behandlung: Ein absolutes No Go! So wie die Nutzung von Label in meinen Augen eine Sache, die jeden Entwickler massiv disqualifiziert. Wer das nur etwas als Hobby macht: klar, toll. Aber das sind so Dinge, die einfach im professionellen Bereich absolut nicht vorkommen dürfen...)
- while(true) - wo kommt eine Endlosschleife in der Aufgabenstellung vor? Das ist ein Anti-Pattern. Wenn etwas getan werden soll, bis die Datei zu Ende gelesen wurde, dann sollte sowas auch in dem Code entsprechend zu finden sein.

Das wäre so auf Anhieb das, was mir auf den ersten Blick aufgefallen ist. Natürlich kommt noch hinzu, dass die Aufgabenstellung nicht verstanden wurde: Da ging es ganz klar um ein Array und nicht um eine ArrayList. Und wo ich das jetzt erwähne: Du hast doch angeblich auch das Buch "Entwurfsmuster von Kopf bis Fuß" gelesen? Da stand doch etwas von wegen "Gegen ein Interface entwickeln und nicht gegen eine Klasse." ... Also statt ArrayList<Geld> solltest Du, bis auf die Erstellung, doch bitte mit List<Geld> arbeiten... Das sind aber dann Clean Code Feinheiten. Darauf musst Du am Anfang noch nicht so eingehen. Die anderen Dinge sind da erst einmal wichtiger...


----------



## Xyz1 (20. Dez 2019)

JustNobody hat gesagt.:


> Also statt ArrayList<Geld> solltest Du, bis auf die Erstellung, doch bitte mit List<Geld> arbeiten... Das sind aber dann Clean Code Feinheiten. Darauf musst Du am Anfang noch nicht so eingehen. Die anderen Dinge sind da erst einmal wichtiger


Das ist mir bewusst, das ist in der Praxis aber eher unnütz, also eher kontraproduktiv. Aber darauf musst Du am Anfang noch nicht so eingehen.


----------



## kneitzel (20. Dez 2019)

Tobias-nrw hat gesagt.:


> Das ist mir bewusst, das ist in der Praxis aber eher unnütz, also eher kontraproduktiv. Aber darauf musst Du am Anfang noch nicht so eingehen.


Ja, sorry. Ich wollte Dich da am Anfang natürlich nicht überfordern. Und das mit der Praxis kommt irgendwann auch mal bei Dir - und dann bekommst Du auch nach und nach Einblick, wie nützlich das Eine oder Andere sein kann. (Hier nur ganz Kurz, weil es auch ein Anfänger verstehen kann: Was für eine List da verwendet wird, ist ja egal. Wenn Da einfach überall nur List verwendet wird, dann kann dieses Implementierungs-Detail mit viel weniger Anpassungen umgesetzt werden.)


----------



## Xyz1 (20. Dez 2019)

JustNobody hat gesagt.:


> Ich wollte Dich da am Anfang natürlich nicht überfordern. Und das mit der Praxis kommt irgendwann auch mal bei Dir - und dann bekommst Du auch nach und nach Einblick, wie nützlich das Eine oder Andere sein kann


Na ja, "Realitätsverweigerung" muss es auch geben.

Allgemein fänd ich es gut, wenn man sich Wissen aneignen würde, bevor man andere Antworten als falsch hinstellen will. Kannst Du das?


----------



## kneitzel (20. Dez 2019)

Danke Tobias für Deine Meinung. Schade, dass es keine Argumente gab. Aber vielleicht nächstes Mal.


----------

