Foreach

Guten Tag

Ich habe eine ArrayList mit Objekten vom Typ kunden.

Nun wird ein KundenObjekt in dieser Liste verändert, und dieses sollte in der Liste gesucht werden und überschrieben.

Das funktioniert alles, jedoch finde ich den zu umständlich… Mit einer foreach Schlaufe durchsuche ich die Liste nach meinem Objekt:

			if (liste.equals(kundenData)) {
				System.out.println("Kunde gefunden");

                                // Hier möchte ich mein Objekt in der Liste ändern

				neuerKunde = false;
				break;
			}
		}```

Nun meine eigentliche Frage, ist es möglich jetzt und hier in dieser Schlaufe mein Objekt direkt in der Liste zu ändern?

Hm, einmal schreibst du “überschreiben”, und einmal “verändern”. Was genau willst du denn jetzt machen?
Du kannst das Objekt, das von liste referenziert natürlich verändern (d.h. Methoden aufrufen die den internen Zustand des Objektes ändern). Wenn du mit überschreiben folgendes meinst:
liste = new KundenListe(...);
dann geht das über diesen Weg so nicht.

Wenn du immer einen eindeutigen KEY hast, zBsp. die KdNr., dann würde sich eine HashMap<int, Kunde> anbieten.
Die nimmt dir dann die lästige Sucherei ab.
public boolean containsKey(Object key) zeigt dir an, obs den Kunden schon gibt.

Gruß Vanny

Das Problem ist etwas schwammig beschrieben.
Haben die Entitäten (Kunden) eine eindeutige ID? Wenn ja, sorgst du dafür, dass es jeweils nur eine Instanz mit derselben ID gibt (Stichwort Identity-Map)?
Die Modellklasse ist in deinen Codefragment nicht eindeutig: im Kundenmodell gibt es Kundendaten, die eine Liste von Kundenlisten sind? Klingt irgendwie komisch, vor allem, weil du in der Schleife ausgibst “Kunde gefunden” und nicht “Kundenliste gefunden”.

neuerKunde = false lässt darauf schließen, dass du eigentlich vorhast, nach frei eingegebenen Kundendaten (Name, Vorname, …) zu suchen.

Das sieht mir nach einer Aufgabe für ein Repository aus, welches eine findByName() (oder welche Kriterien auch immer du hast) Methode anbietet und dann die Entität zurückgibt (falls kein Treffer, wird normalerweise null zurückgegeben).

Also nochmal, ich möchte diese Liste mit KundenObjekten durchsuchen ob dieser Kunde der eingegeben wurde bereits vorhanden ist.

Wenn ja möchte ich das alte KundenObjekt mit dem neuen überschreiben so dass die Liste immer aktuell ist.

Den Vorteil einer HashMap seh ich hier nicht da ich die Daten ja in einer ObservableList habe und sie dann vorher in eine HashMap stecken müsste oder?

Mit dem: neuerKunde = false merke ich mir nur ob der Kunde in der Liste vorhanden ist. Gemässt boolean status kommt nachher die reaktion ob überschreiben oder neu anlegen. und das ist mir
viel zu umständlich.

Darum kam die frage ob man das KundenObjekt in der Liste suchen kann, und gleich wenn vorhanden, die neuen Werte in der Liste in das KundenObjekt zu schreiben.

*** Edit ***

Nun hab ich es mit einer herkömmlichen Schlaufe gelöst, nur ist das der richtige weg?

			if (kundenData.equals(kundenModel.getKundenDaten().get(i))) {
				kundenModel.setKundenDaten(kundenData, i);

				neuerKunde = false;
			}
		}```

Du hast meine Fragen nicht beantwortet… So kann man dir nicht helfen. Der Equalsvergleich legt nahe, dass du den selben Kunden in mehreren Objektinstanzen abspeicherst. Das ist eher suboptimal.
Deine Schleife (nicht Schlaufe!) gehört in eine separate Methode innerhalb des Kundenmodells:

...
    public boolean contains(Kunde o) {
        for (Kunde kunde : this.kundenListe) {
            if (kunde.equals(o)) {
                return true;
            }
        }
        return false;
    }
}```

Nichtsdestotrotz hast du deine Anforderungen nicht spezifiziert. Dein Modell sieht komplett daneben aus. Du scheinst mit getKundenDaten() eine Kundenliste auszugeben: falscher Methodenname. getKundenListe() wäre angebrachter. Mit dem getter gibst du auch noch ein Implementierungsdetail nach außen weiter (du verwendest eine List zum Speichern der Kunden). Noch schlimmer, du verletzt das Prinzip "Tell, don't ask", indem du außerhalb der KundenModell-Klasse über die Einträge der Kundenliste iterierst. Wenn du jetzt an einer weiteren Stelle prüfen müsstest, ob ein Kunde bereits in der Liste steht, kannst du gleich diese Schleife 1:1 kopieren. Wenn sich dann die Art, wie du die Kunden speicherst, ändert, dann kannst du gleich alle Stellen an denen du einen Kunden prüfst suchen und ändern. Abhilfe schafft der Ansatz mit der in diesem Beitrag geposteten Methode (die du aber wahrscheinlich auch gar nicht brauchst, weil das, was du machen möchtest, wahrscheinlich was ganz anderes ist).

Also: mehr Infos!

Du hast völlig recht… In jedem Punkt

Die equals Methode überschreibe ich um alle eingaben (Strasse, Hausnummer, usw…) einzeln auf Gleichheit zu prüfen. Es gibt pro Adresse nur ein Kunde, und umgekehrt!

Nun hab ich diese Methode ins Model gepackt:

	 * Ueberprueft die Liste ob der Kunde bereits vorhanden ist
	 * 
	 * Aendert einen vorhandenen
	 * 
	 * Fuegt einen neuen hinzu
	 * 
	 * @param liste
	 * @return (boolean) Kunde vorhanden
	 */
	public boolean searchAndUpdate(KundenListe liste) {

		// Sucht ob der Kunde vorhanden ist
		// und aendert diesen
		for (int i = 0; i < kundenDaten.size(); i++) {
			if (liste.equals(kundenDaten.get(i))) {
				kundenDaten.set(i, liste);

				return true;
			}
		}

		// Falls nicht vorhanden
		kundenDaten.add(liste);
		return false;
	}```

Nun gibt mir diese Methode als Rückmeldung ob der Kunde vorhanden ist, dann wurde der Eintrag aktualisiert. Wenn nein wurde er in der Liste neu angelegt.

Aber mein Problem ist so eigentlich gelöst, ich wollte es ja einfacher haben...

Das passt immer noch nicht. Die Methode gehört eigentlich eher in den ServiceLayer (so denn vorhanden). Hast du eine Persistenzschicht?

Außerdem passt der Rückgabewert nicht zum Methodennamen. Warum sollte eine Methode “searchAndUpdate” zurückgeben, ob der Kunde vorhanden ist? Und vor allem stimmt der Rückgabewert nicht mit der Beschreibung überein, denn er gibt den Zustand vor dem Hinzufügen an. “Kunde vorhanden” ist nach der Ausführung immer wahr.

“Separation of Concerns” ist auch nicht eingehalten. Das abfragen, ob es einen Kunden schon in der Liste gibt hat erstmal nichts mit dem Hinzufügen zu tun. Was ist, wenn du mal nur wissen möchtest, ob ein Kunde schon in der Liste ist, ohne den zu prüfenden Kunden hinzuzufügen? Das ginge dann nicht, ohne den Code zu duplizieren (oder herauszufaktorisieren in die Methode, in die er gehört: contains(Kunde)).

KundenListe passt von der Bezeichnung her auch noch nicht. Laut JavaDocs ist das doch ein einzelner Kunde ("… ob der Kunde…", “Aendert einen vorhandenen”, “Fuegt einen…”, …). Ist es denn ein einzelner Kunde oder eine Liste?

Jetzt wo du es erwähnst… Also die KundenListe hab ich geändert in Kunde

aus einer Methode hab ich jetzt drei gemacht, suchen, updaten, oder neu.

	 * Ueberprueft die Liste ob der Kunde bereits vorhanden ist
	 * 
	 * @param liste
	 * @return (boolean) Kunde vorhanden
	 */
	public boolean getKundeVorh(Kunde kunde) {

		// Sucht ob der Kunde vorhanden ist
		// und aendert diesen
		for (int i = 0; i < kundenDaten.size(); i++) {
			if (kunde.equals(kundenDaten.get(i))) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Updatet einen vorhanden Kunden
	 * 
	 * @param kunde
	 */
	public void updateKunde(Kunde kunde) {
		// Sucht ob der Kunde vorhanden ist
		// und aendert diesen
		for (int i = 0; i < kundenDaten.size(); i++) {
			if (kunde.equals(kundenDaten.get(i))) {
				kundenDaten.set(i, kunde);
				break;
			}
		}
	}

	/**
	 * Fügt einen neuen Kunde hinzu
	 * 
	 * @param kunde
	 */
	public void newKunde(Kunde kunde) {
		kundenDaten.add(kunde);
	}```

Ich arbeite mit dem MVC prinzip, was verstehst du von ServiceLayer oder Persistenzschicht?

*** Edit ***

Ah ja eine Persistenzschicht möchte ich haben, ich arbeite mit einer HSQLDB!

Aber im diese ist noch nicht implementiert! Ich stelle mir das so vor das bei jeder änderung der Liste, auch ein abgleich mit der DB stattfindet!

Die Persistenzschicht ist bei einem 3 Schichten-Modell die unterste Schicht, die die Objekte dauerhaft (persistent) speichert und vom Speicher wieder lädt. Häufig verwendet man einen ServiceLayer, also eine Abstraktionsebene, in der Klassen sind, die die Methoden anbieten, um Objekte zu Laden, Aktualisieren und Löschen (CRUD: Create, Read, Update, Delete). Zum Laden gibt es dann häufig mehrere Methoden, die verschiedene Abfragekriterien bieten (findByName, findAll, findByFirstNameAndLastName, …).
Die zweite Schicht im 3 Schichten-Modell ist die Domänenschicht, in der das Modell deiner Anwendung liegt. Dort werden alle Funktionen abgebildet, die deine Anwendung bieten soll.
Die dritte Schicht ist die Darstellungsschicht. Dafür verwendest du das MVC-Pattern.

*** Edit ***

Ebenfalls so, wie ich es vermutet habe. Also bräuchtest du einen Servicelayer, den du fragen kannst, ob es einen bestimmten Kunden schon gibt. Normalerweise hast du nämlich nicht alle Objekte im Speicher (wäre unpraktisch, wenn du Millionen von Kunden verwaltest).
Eine eigene Persistenzschicht zu entwickeln birgt ziemlich viele Hindernisse. Martin Fowler beschreibt in “Patterns of Enterprise Application Architecture” sehr ausführlich den Aufbau von derartigen Anwendungen. Das ist nämlich nicht mal eben in zwei Sätzen erklärt. Du wirst wahrscheinlich erstmal mit JDBC arbeiten wollen, aber ein ausgereiftes ORM (Object-Relational-Mapping) Framework wie Hibernate nimmt dir sehr viel Arbeit ab.
Ein Kernproblem ist die Verwaltung von bereits geladenen Instanzen (kann man mit einer IdentityMap machen). Es darf kein Kunde (für deinen Anwendungsfall) doppelt geladen werden, weil du ansonsten Änderungen am einen Objekt im anderen nicht bemerkst und ggf. Änderungen mit der anderen Instanz überschreibst.
Ein weiteres Kernproblem ist das Laden von ganzen Objektgraphen. Wenn das Modell eng gekoppelt ist, kann es sein, dass du den gesamten Objektgraphen auf einmal lädst, wenn du kein LazyLoad machst.

Die Software die ich da am schreiben bin sollte am Schluss relativ komplex werden.

Zusammen mit JavaFX, nehme ich mal dass ich sofort auf Hibernate gehen sollte? Weil ich finde langsam könnten meine Software auch umfangreicher werden. Und wenn mir das arbeit abnimmt sollte ich es auch lernen.

Mit JavaFX hat das weniger zu tun. Das kommt eher auf die Komplexität deines Domänenmodelles an. Wenn du recht umfangreiche Graphen hast, dann wird das schnell sehr schwierig mit dem Laden der Objekte. Ein Persistenzframework nimmt dir da den Großteil der Arbeit ab.

Interessant finde ich auch Spring Data, das nimmt einem dann auch gleich noch den Großteil der Erstellung des ServiceLayer ab. Da muss man dann aber gleich noch Spring und auch JPA benutzen (ok, es gibt verschiedene Implementierungen, aber die Konstellation Spring Data, JPA und Hibernate als JPA Implementierung macht eine ziemlich gute Figur).

ahso, dann werd ich das wohl noch sein lassen… Ich denke die Liste wird nie mehr als 1000 Einträge haben…

Was mich jetzt am ganzen noch interresieren würde, gibt es eine möglichkeit von aussen informiert zu werden wenn sich etwas an der liste geändert hat?

Du hast das oben so angesprochen… Weil dann könnte ich relativ einfach die Verbindung zu einer DB machen

Verstehe ich nicht so ganz.
Die Liste wird ja von deiner Anwendung verwaltet. Dazu muss die Liste gekapselt sein (darauf habe ich oben ja schon hingewiesen: “Mit dem getter gibst du auch noch ein Implementierungsdetail nach außen weiter (du verwendest eine List zum Speichern der Kunden).”). Wenn sie nicht gekapselt ist, also per Getter abgerufen und dann verändert werden kann, ist es nicht möglich eine Hinzufügeoperation zu bemerken.
Wenn du ein sauberes Design hast und die Liste ein verstecktes Implementierungsdetail ist, fügst du Kunden über so etwas wie CustomerModel#addCustomer(Customer customer) hinzu und kannst innerhalb dieser Methode das Observerpattern implementieren und eine Notification an die Observer schicken.

[quote=headnut]Was mich jetzt am ganzen noch interresieren würde, gibt es eine möglichkeit von aussen informiert zu werden wenn sich etwas an der liste geändert hat?[/quote]Wo möglich ist es sinnvoll Dein Model [JAPI]TableModel[/JAPI] und/oder [JAPI]ListModel[/JAPI] implementieren zu lassen. Dann können sich Interessierte (z.B. JTable oder JList) über Änderungen informieren lassen…
[Edit]: wir waren ja bei FX und nicht bei Swing, aber ich schätze da gibt es ähnliches…

bye
TT