Probleme mit Collections im Konstruktor

bugbunny

Mitglied
Hallo,
ich habe ein Verständnisproblem bei einer Hausaufgabe.
Es gibt einmal die Klasse Spieler die das Interface Comparable<Spieler> implementieren soll und die Spieler nach ihrer id vergleichen soll.

Das habe ich so "gelöst":
Java:
public class Spieler implements Comparable<Spieler>
{ 
int id;
String name;

public static List<Spieler> spieler = new ArrayList<Spieler>();

@Override
public int compareTo(Spieler other)
{    if (getId() > other.getId())
    {        return 1;
    } else if (getId() < other.getId())
    { return -1;
    } else return 0;
}
public Spieler(int id, String name)
{
    if (id < 0 || name.isEmpty())
        throw new IllegalArgumentException( "Id negativ oder name leer" );

    this.id = id;
    this.name = name;
    spieler.add( this );
    Collections.sort( spieler );
}
Zum Testen habe ich mir ein paar Spieler erstellt und mir die Liste einmal unsortiert und dann mit Collections.sort sortiert, das funktioniert.

Dann soll ich in der Klasse Spielermanager folgendes machen:
public SpieleManager(Collection<Spieler> spieler)
Erzeugt einen SpielerManager, dem die übergebenen Spieler bekannt sind.
Befinden sich in der übergebenen Collection mehrere Spieler mit der gleichen ID oder
dem gleichen Namen oder kennt der SpielerManager bereits Spieler mit der ID oder dem
Namen eines übergebenen Spieler, soll eine java.lang.IllegalArgumentException geworfen werden.
Die übergebene Collection darf (auch bei Aufrufen weiterer Methoden dieser Klasse)
nicht verändert werden.

Ich verstehe nicht wie das mit dem Übergeben der Liste funktionieren soll, kann mir das jemand erklären oder hat eine gutes Beispiel?

Grüße Leonie
 

Robat

Top Contributor
Was genau verstehst du daran nicht? Die Signatur des Konstruktors hast du ja schon. Jetzt musst du nur noch eine Liste von Spielern erzeugen und diese dem Konstruktor übergeben.
Java:
public static void main(String[] args) {
    List<Spieler> spieler = new ArrayList<>();
    // liste füllen
 
    SpielerManager manager = new SpielerManager(spieler);
}
Java:
public class SpielerManager {
     private List<Spieler> spieler;
     public SpielerManager(Collection<Spieler> spieler) {
           ...
     }
}
BTW: Warum besitzt die Klasse Spieler eine Liste von Spielern?
 

bugbunny

Mitglied
Ist meine erste größere Aufgabe, deswegen sind mir manchmal die Zusammenhänge was in welcher Klasse passiert noch nicht ganz klar, hier hatte ich bspw. durch das implements Collection<Spieler> im Manager angenommen, dass die Liste dann schon in der Spielerklasse sein muss.

Ok, das bedeutet in der Spielerklasse habe benötige ich nur die compareTo() und die Spielerliste wird erst im Manager deklariert?
Dann kann ich aber die erzeugten Spieler nicht mehr über den Spielerkonstruktur direkt in die Liste speichern?

Und gibt es zur Duplikatserkennung eine einfache Möglichkeit?
 

Javinner

Top Contributor
bugbunny hat gesagt.:
Ok, das bedeutet in der Spielerklasse habe benötige ich nur die compareTo() und die Spielerliste wird erst im Manager deklariert?
Eine Klasse sollte nur Daten und Methoden beinhalten, welche unmittelbar mit der Klasse zutun haben.
Eine Spielerliste ist ganz sicher kein Bestandteil der Klasse Spieler.
Und gibt es zur Duplikatserkennung eine einfache Möglichkeit?
Abfrage beim Hinzufügen zur Liste, ob bereits vorhanden.
 

Robat

Top Contributor
Dann kann ich aber die erzeugten Spieler nicht mehr über den Spielerkonstruktur direkt in die Liste speichern?
Das sollst du ja auch nicht.
So wie ich das anhand des gegebenen Codes / Textes sehe soll der SpielerManager am Anfang eine Collection von Spielern bekommen.
Hinzufügen von Spielern wird sicherlich über eine separate Methode geschehen.
 

bugbunny

Mitglied
Danke für die Hilfe, aber je mehr ich mich "einarbeite" desto weniger verstehe ich :(

Robat du hast recht, die nächste Methode ist
public Player add(Player player)
Fügt dem PlayerManager einen Player hinzu und gibt ihn zurück.
Kennt der PlayerManager bereits Player mit der ID oder dem Namen des übergebenen
Players, soll eine java.lang.IllegalArgumentException geworfen werden.

Nicht einmal das bekomme ich hin, bisher habe ich immer alles in der Mainmethode mit add() hinzugefügt und auch alle Erklärungen die ich die letzten Stunden angeschaut habe waren direkt in der main.

die add methode wird also mit return player; enden oder?
public Player add(Player player){
players.add( player );
return player;}
wird falsch sein, aber wie stelle ich das hinzufügen und die Überprüfung dar? Ich kann verstehen wenn ihr mir nicht die Lösung dazu sagen wollt, aber vielleicht habt ihr ein gutes Beispiel zum verstehen.

Und wieso muss ich in der Methode noch eine IllegalArgumentExeption werfen, wenn Name oder ID schon vorhanden sind, im PlayerManagerKonstruktor wird doch schon bei den selben Bedingungen eine geworfen?

Entschuldigt die vielleicht blöden Fragen.

Grüße Leonie
 

Robat

Top Contributor
Java:
public Player add(Player player){
   players.add( player );
   return player;
}
Sieht aber ganz gut aus.
Naja du musst dir jeden Spieler aus der Liste einmal anschauen (Tipp: Schleife) und die ID mit der ID vom Spieler der hinzugefügt werden soll vergleichen.
Solltest du die selbe ID gefunden haben darf der Spieler nicht hinzugefügt werden.

Und wieso muss ich in der Methode noch eine IllegalArgumentExeption werfen[...]
Du musst sie noch mal werfen, weil die Bedingung ja nur einmal geprüft wird. Du sollst aber zstl. noch bei jedem hinzufügen prüfen, ob die Spieler-ID schon vorhanden ist.
 

bugbunny

Mitglied
Java:
for (Player player: players){
    if(players.contains( player)){
     throw new IllegalArgumentException( "" );
     }
    else players.add( player );
}
return player;
Das ist mein aktueller Stand, aber ich weiß nicht wie ich einzeln auf Name oder ID prüfen kann, funktioniert das mit contains überhaupt?
 

MoxxiManagarm

Top Contributor
Naja du musst dir jeden Spieler aus der Liste einmal anschauen (Tipp: Schleife) und die ID mit der ID vom Spieler der hinzugefügt werden soll vergleichen.

Nicht unbedingt. Er könnte im PlayerManager intern auch eine Datenstruktur verwenden, welche keine Duplikate zulässt und entsprechende Rückgabewerte liefert, sofern das neue Element nicht ergänzt werden kann.

z.B. https://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html#add(E)

Das wäre im Fall von TreeSet sogar auch gleich sortiert, falls das in den weiteren Schritten mal irgendwie eine Rolle spielen sollte.

Das ist mein aktueller Stand, aber ich weiß nicht wie ich einzeln auf Name oder ID prüfen kann, funktioniert das mit contains überhaupt?

Ich glaube nicht, es wird m.E. die equals Methode verwendet. Du könntest diese aber auch überschreiben.

Unabhängig davon macht keinen Sinn das innerhalb der Schleife zu tun. Entweder in der Schleife einzeln vergleichen, oder contains oder wie oben eine Datenstruktur, welche duplikatslos ist.
 
Zuletzt bearbeitet:

MoxxiManagarm

Top Contributor
Ich sehe insgesamt 5 Alternative Implementierungen.
Java:
public static void main(String[] args) {
            DuplicateDemo demo = new DuplicateDemo();
          
            System.out.println(demo.addIdObject(new IdObject(1)));
            System.out.println(demo.addIdObject(new IdObject(2)));
            System.out.println(demo.addIdObject(new IdObject(3)));
            System.out.println(demo.addIdObject(new IdObject(3)));
      }

Alle Beipsiele bringen damit die Ausgabe 1, 2, 3, null

Mein IdObject hat folgende Methoden @Override: equals, compareTo, toString
Sowie getId()

Alternative 1-4 ist z.B. eine ArrayList
Alternative 5 ist z.B. ein TreeSet

Alternative 1: Vergleich via überschriebener equals Methode
Java:
public IdObject addIdObject(IdObject o) {
            for(IdObject obj : list) {
                  if(obj.equals(0)) return null;
            }
            list.add(o);
            return o;
      }

Alternative 2: Vergleich via überschriebener compareTo Methode
Java:
public IdObject addIdObject(IdObject o) {
            for(IdObject obj : list) {
                  if(obj.compareTo(o) == 0) return null;
            }
            list.add(o);
            return o;
      }

Alternative 3: Direktvergleich
Java:
public IdObject addIdObject(IdObject o) {
            for(IdObject obj : list) {
                  if(obj.getId() == o.getId()) return null;
            }
            list.add(o);
            return o;
      }

Alternative 4: contains
Java:
public IdObject addIdObject(IdObject o) {
            if(list.contains(o)) return null;
          
            list.add(o);
            return o;
      }

Alternative 5: Duplikatsfreie Datenstruktur
Java:
public IdObject addIdObject(IdObject o) {
            return set.add(o) ? o : null;
      }
 

mrBrown

Super-Moderator
Mitarbeiter
Es gibt einmal die Klasse Spieler die das Interface Comparable<Spieler> implementieren soll und die Spieler nach ihrer id vergleichen soll.
Erzeugt einen SpielerManager, dem die übergebenen Spieler bekannt sind.
Befinden sich in der übergebenen Collection mehrere Spieler mit der gleichen ID oder
dem gleichen Namen oder kennt der SpielerManager bereits Spieler mit der ID oder dem
Namen eines übergebenen Spieler, soll eine java.lang.IllegalArgumentException geworfen werden.
Sind diese beiden Teile korrekt aus der Aufgabenstellung zitiert?

Wenn ja, fallen alle Varianten mit equals oder Comparator/Comparable weg, da man den jeweilige Methode-Contract brechen müsste.
Es bleibt also nur die Variante mit direktem Vergleich der beiden Attribute, in deinem Fall am einfachste mit einer Schleife über die Liste.
 

MoxxiManagarm

Top Contributor
Oh das mit dem Namen habe ich überlesen. Dann bleibt eigentlich nur Variante 3.

Edit: Habe den 2. Teil herausgelöscht, war Blödsinn in zusammenhang mit der Aufgabenstellung
 
Zuletzt bearbeitet:

bugbunny

Mitglied
Danke für die vielen Antworten, ich habe meinen Code mal umgebastelt und mit meinem Verständnis kommentiert.
Java:
for(Spieler s : spieler) //durchläuft die Liste spieler wenn neuer Spieler erzeugt wird
{    if (s.getId() == spieler.getId()) //Wenn Id des erzeugten Spielers bereits in Liste vorhanden ist, wird Exception geworfen
    {        throw new IllegalArgumentException( "ID bereits vorhanden" );
    }
    if (s.getName().equals(.getName() )) //Gleicher Test für name, nur equals da String
    {        throw new IllegalArgumentException( "Name bereits vorhanden");
    }
}
    spieler.add( spieler ); //fügt Spieler der Liste hinzu
    return spieler; // gibt hinzugefügten Spieler zurück
}
Stimmt das in etwa?
Und funktioniert der equalsvergleich von name auch wenn ich in der Spielerklasse die equals Methode so überschrieben habe, dass zwei Spieler gleich sind wenn sie die gleich ID haben? Wurde nämlich gefordert.

Und noch etwas verstehe ich nicht: Wenn ich mir in der main-Methode Spieler erstelle und die mit Add der Liste hinzufüge, wird nicht meine neue add Methode genommen, sondern die ganz normale Listen.add ohne Prüfung, wie kann ich auf meine neue zugreifen?
 

mrBrown

Super-Moderator
Mitarbeiter
Und funktioniert der equalsvergleich von name auch wenn ich in der Spielerklasse die equals Methode so überschrieben habe, dass zwei Spieler gleich sind wenn sie die gleich ID haben? Wurde nämlich gefordert.
Ja, name ist ein String und hat nichts mit dem in der anderen klasse überschriebenem equals zu tun ;)

Und noch etwas verstehe ich nicht: Wenn ich mir in der main-Methode Spieler erstelle und die mit Add der Liste hinzufüge, wird nicht meine neue add Methode genommen, sondern die ganz normale Listen.add ohne Prüfung, wie kann ich auf meine neue zugreifen?
Du solltest die Spieler nicht einer Liste hinzufügen, sondern einem Spielermanager ;)
 

Neue Themen


Oben