String vergleichen

Rahza

Mitglied
Hi Leute,

ich habe vor einigen Wochen begonnen in Java zu programmieren im Rahmen eines Informatik-Moduls an der Uni.
Nun haben wir eine Aufgabe, wo es darum gibt, die Themen Vererbung, Schnittstellen etc. umzusetzen.
Die Uni stellt einen Autokorrektor bereit, der anhand von vorgefertigten Test eventuelle Fehler aufdeckt. Der Autokorrektor zeigt einen Fehler an, wo ich nicht mehr weiterkomme. Wäre toll, wenn ihr mir da einen Tipp geben könntet:
Java:
public abstract class Milchprodukt extends Produkt implements Produzierbar{
   
    private double fettgehalt;
    private Zutat[] zutaten = new Zutat[10];
   
    public Milchprodukt() {}
    public boolean produzieren(int anzahl) {
        for (int i=0; i<10; i++) {
            if(zutaten[i].getAnzahlVerfuegbarerEinheiten()>=anzahl) {
                setAnzahlVorhanden(getAnzahlVorhanden() + anzahl);
                zutaten[i].setAnzahlVerfuegbarerEinheiten(zutaten[i].getAnzahlVerfuegbarerEinheiten() - anzahl);
                return true;
            }
               
        }
        return false;
       
    }
   
    public boolean addZutat(Zutat zutat) {
        boolean contains=false;;
        for (int i=0; i<10; i++) {
            if((zutaten[i].getName()).equals(zutat.getName())) {
                contains=true;
                return false;
            }
        }
        for (int i=0; i<10; i++) {
            if (zutaten[i]==null||!contains) {
                zutaten[i].setName(zutat.getName());
                break;
            }
        }
        return true;
    }
   
    public boolean removeZutat(Zutat zutat) {
       
        for (int i=0; i<10; i++) {
            if(zutaten[i].getName().equals(zutat.getName())) {
                zutaten[i].setName(null);
                return true;
            }
        }
        return false;
    }
   
    public double getFettgehalt() {
        return fettgehalt;
    }

    public void setFettgehalt(double fettgehalt) {
        this.fettgehalt = fettgehalt;
    }

    public Zutat[] getZutaten() {
        return zutaten;
    }

    public void setZutaten(Zutat[] zutaten) {
        this.zutaten = zutaten;
    }
}

Der Fehler wird in der Methode addZutat in der ersten If-Schleife angezeigt, wo es um den Vergleich der Strings geht.

Vielen Dank.

Ich kann gerne die Aufgabenstellung hier reinstellen, allerdings gehören dazu mehrere anderen, eigentlich relativ einfache, Klassen dazu. Ich glaube aber, dass es eher ein simpler Fehler ist, wo ich einfach irgendwas übersehen.
Noch was zur Methode addZutat, um die es geht:
Die Methode soll im vorgegebenen Zutaten-Array prüfen, ob es die Zutat schon gibt. Falls ja, soll false zurückgegegben werden und falls nicht, soll die Zutat an einer freien Stelle eingefügt werden und es soll true zurückgegeben werden.
 
Nach dem ersten getName() ist eine Klammer zuviel.

Und contains brauchst du nicht.

Außerdem würde ich auf die fest codierte 10 bei i<10 verzichten und lieber zutaten.length nehmen. "magic values" sind böse.
 
Ich kann gerne die Aufgabenstellung hier reinstellen, allerdings gehören dazu mehrere anderen, eigentlich relativ einfache, Klassen dazu. Ich glaube aber, dass es eher ein simpler Fehler ist, wo ich einfach irgendwas übersehen.
Noch was zur Methode addZutat, um die es geht:
Die Methode soll im vorgegebenen Zutaten-Array prüfen, ob es die Zutat schon gibt. Falls ja, soll false zurückgegegben werden und falls nicht, soll die Zutat an einer freien Stelle eingefügt werden und es soll true zurückgegeben werden.
Wir kennen die Aufgabe schon. 😎 Offenbar gibt es auch Licht am Ende des Tunnels. Musst du nicht verstehen.😉
 
Nach dem ersten getName() ist eine Klammer zuviel.

Und contains brauchst du nicht.

Außerdem würde ich auf die fest codierte 10 bei i<10 verzichten und lieber zutaten.length nehmen. "magic values" sind böse.

Ich hatte die Klammer sowohl am Anfang, als auch am Ende hinzugefügt, wegen dem Equals. Änder es aber nochmal um, aber trotz Änderung hat es nicht funktioniert bzw. der Fehler wird angezeigt. Hab auch length schon probiert.
Wegen contains: Das habe ich genutzt, damit das Programm nur dann einfügt, falls die Zutat nicht bereits enthalten ist. Oder klappt das ohnehin wegen dem return false?
 
Noch ein Hinweis: Was denkst du was passiert, wenn du zutaten[i].getName() aufrufst und die Stelle im Array ein null enthält?
 
Noch ein Hinweis: Was denkst du was passiert, wenn du zutaten[i].getName() aufrufst und die Stelle im Array ein null enthält?
Es müsste dann false zurückgegeben werden, da dann der Name der Zutat offensichtlich nicht mit Null übereinstimmt. Oder meinst du dass dann die Equals-Abfrage nicht klappen kann, da Null kein String ist.
 
Noch ein Hinweis: Schau dir auch produzieren() noch mal an. Die Aufgabe verlangt, dass von jeder verfügbaren Zutat, mindestens die geforderte Anzahl vorhanden sein muss, bevor produziert werden kann. Überleg dir mal, was passiert, wenn bei dir eine Zutat die nicht die richtige Menge hat.
 
Es müsste dann false zurückgegeben werden, da dann der Name der Zutat offensichtlich nicht mit Null übereinstimmt. Oder meinst du dass dann die Equals-Abfrage nicht klappen kann, da Null kein String ist.

Ich meine eher eine NullPointerException 😉 Auf ein nicht existierendes Objekt kann man keine Methode aufrufen.
 
Das ist übrigens jetzt der Code mit dem was ihr vorgeschlagen habt, aber es wird immer noch
java.lang.NullPointerException angezeigt bzw. dieses addZutat klappt nicht wirklich, da im späteren Verlauf des Tests der Aufruf der Methode fehlschlägt

Java:
public boolean addZutat(Zutat zutat) {
        
        for (int i=0; i<zutaten.length; i++) {
            if(zutaten[i].getName().equals(zutat.getName())) {
                
                return false;
            }
        }
        for (int i=0; i<10; i++) {
            if (zutaten[i]==null) {
                zutaten[i].setName(zutat.getName());
                break;
            }
        }
        return true;
    }
    
    public boolean removeZutat(Zutat zutat) {
        
        for (int i=0; i<10; i++) {
            if(zutaten[i].getName().equals(zutat.getName())) {
                zutaten[i].setName(null);
                return true;
            }
        }
        return false;
    }
 
Wie schon angedeutet: Die Abfrage muss lauten:

"wenn zutat nicht null ist und der name der zutat gleich dem namen den neuen zutat ist, dann"

Das gilt für alle deine Methoden, wo du dieses Array verwendest, weil immer auch null-Werte drin sein können.
 
Ich meine eher eine NullPointerException 😉 Auf ein nicht existierendes Objekt kann man keine Methode aufrufen.
Wäre es dann sinnvoll eventuell die Abfrage, ob das Element enthalten ist, als zweites durchzuführen und als erstes einfach das Element an einer freien Stelle zu setzen? Bzw. wie kann ich das umgehen, dass er die Null's abfragt?
 
Bzw. wie kann ich das umgehen, dass er die Null's abfragt?
Siehe Antwort darüber: Du darfst die Methode einfach nicht aufrufen, wenn das Element null ist.

Die logische Verknüpfung && bricht ab, wenn bereits der erste Vergleich nicht true ergibt. Der Vergleich nach dem && wird dann nicht mehr durchgeführt. Bingo!
 
Hab es jetzt so umgeändert, aber es wird ein Fehler angezeigt: Null pointer access: The variable zutat can only be null at this location

Hatte vorher die Abfragen getauscht, also erst den Namensvergleich und danach angefragt dass zutat!=null, da gab es zwar keinen Compiler-Fehler aber im Public-Test

Java:
public boolean addZutat(Zutat zutat) {
        
        for (int i=0; i<zutaten.length; i++) {
            if(zutat!=null||zutaten[i].getName().equals(zutat.getName())) {
                
                return false;
            }
        }
        for (int i=0; i<10; i++) {
            if (zutaten[i]==null) {
                zutaten[i].setName(zutat.getName());
                break;
            }
        }
        return true;
    }
 
Also was mich etwas wundert ist, dass Du beim Löschen nur den Namen auf null setzt. Und beim Einfügen nur den Namen setzen willst.

Das ist durchaus möglich. Dann müsstest Du bei der Initialisierung im Array auf jeder Position eine neue Zutat mit name=null initialisieren. Dann wäre auch die Prüfung auf null nicht mehr notwendig, denn alle Elemente sind dann ja gesetzt.

Das wäre also sowas wie: Du hast ein Gewürzregal mit Schubladen. Die Schubladen sind schon da, aber sind nicht beschriftet. Und wenn Du eine Zutat komplett entfernst, dann wird nur das Namensschild entfernt....

Üblich ist aber etwas anderes: Du entfernst nicht nur den Namen sondern die ganze Instanz von Zutat wird entfernt. Dann ist das Array selbst leer, sprich: Es enthält dann null Werte. Wenn Du da nun eine Zutat auf einen Platz stellen willst, erzeugst Du ein neues Zutaten Objekt und fügst das ein. Und das Löschen wäre dann auch, dass die Position auf null gesetzt wird und nicht der Name.
 
Soweit bin ich jetzt, aber der Fehler wird noch angezeigt. Ich denke mal das hängt mit dem zusammen was JustNobody geschrieben hat

Code:
public boolean addZutat(Zutat zutat) {
        
        for (int i=0; i<zutaten.length; i++) {
            if(zutat!=null&&zutaten[i].getName().equals(zutat.getName())) {
                
                return false;
            }
        }
        for (int i=0; i<10; i++) {
            if (zutaten[i]==null) {
                zutaten[i].setName(zutat.getName());
                break;
            }
        }
        return true;
    }
    
    public boolean removeZutat(Zutat zutat) {
        
        for (int i=0; i<10; i++) {
            if(zutat!=null&&zutaten[i].getName().equals(zutat.getName())) {
                zutaten[i].setName(null);
                return true;
            }
        }
        return false;
    }
 
Also was ich meine noch einmal etwas am Code aufgezeigt:
Sieh einfach mal Zutat als eine Schublade in einem Regal. Dann hast Du hier z.B.:

Java:
        for (int i=0; i<10; i++) {
            if (zutaten[i]==null) {
                zutaten[i].setName(zutat.getName());
                break;
            }
        }

Also Du prüfst: Ist an Position i keine Schublade?
Wenn das der Fall ist, dann sagst Du: An der Schublade an Position I setzt du den Namen.

Also Ich frage Dich "Hast Du ein Auto?" -> "Nein." Und dann "Dann öffne bitte einmal den Kofferraum Deines Autos."

Und dann auch noch etwas zum nachdenken:
Wenn Deine Geldbörse ein addGeldschein(Geldschein) hat: Dann erwartest Du doch, dass der übergebene Gedschein in die Geldbörse kommt. Und nicht, dass jemand ein Stück Zettel nimmt, da dann den Betrag des Geldscheines drauf schreibt und dann den Zettel in die Geldbörse steckt ...
 
Code:
if(zutat!=null&&zutaten[i].getName().equals(zutat.getName())) {

zutat := Zutatenregal
zutat[i] := Schublade an Position i

Damit prüfst Du: Gibt es das Zutatenregal und ist der Name auf der i.ten Schublade der von der übergebenen Schublade.
Das Zutatenregal gibt es aber Dich interessiert ja, ob es eine Schublade gibt. Und nur wenn es eine Schublade gibt, kannst Du den Namen prüfen. Also was müsstest Du prüfen?
 
Also was ich meine noch einmal etwas am Code aufgezeigt:
Sieh einfach mal Zutat als eine Schublade in einem Regal. Dann hast Du hier z.B.:

Java:
        for (int i=0; i<10; i++) {
            if (zutaten[i]==null) {
                zutaten[i].setName(zutat.getName());
                break;
            }
        }

Also Du prüfst: Ist an Position i keine Schublade?
Wenn das der Fall ist, dann sagst Du: An der Schublade an Position I setzt du den Namen.

Also Ich frage Dich "Hast Du ein Auto?" -> "Nein." Und dann "Dann öffne bitte einmal den Kofferraum Deines Autos."

Und dann auch noch etwas zum nachdenken:
Wenn Deine Geldbörse ein addGeldschein(Geldschein) hat: Dann erwartest Du doch, dass der übergebene Gedschein in die Geldbörse kommt. Und nicht, dass jemand ein Stück Zettel nimmt, da dann den Betrag des Geldscheines drauf schreibt und dann den Zettel in die Geldbörse steckt ...
Danke für die ausführliche Erklärung. Die Grundidee habe ich schon verstanden. Hab da einfach gedacht, dass wenn ich den Namen "reinlege", dann ist es damit getan.
Java:
    public boolean addZutat(Zutat zutat) {
        
        for (int i=0; i<zutaten.length; i++) {
            if(zutaten[i]!=null&&zutaten[i].getName().equals(zutat.getName())) {
                
                return false;
            }
        }
        for (int i=0; i<10; i++) {
            if (zutaten[i]==null) {
                zutaten[i]=zutat;
                break;
            }
        }
        return true;
    }
    
    public boolean removeZutat(Zutat zutat) {
        
        for (int i=0; i<10; i++) {
            if(zutaten[i]!=null&&zutaten[i].getName().equals(zutat.getName())) {
                zutaten[i]=null;
                return true;
            }
        }
        return false;
    }
 
Noch ein Hinweis: Schau dir auch produzieren() noch mal an. Die Aufgabe verlangt, dass von jeder verfügbaren Zutat, mindestens die geforderte Anzahl vorhanden sein muss, bevor produziert werden kann. Überleg dir mal, was passiert, wenn bei dir eine (oder mehrere) Zutat die nicht die richtige Menge hat.

Und kümmere dich noch um die 10 bei den Schleifen.
 
Code:
    public boolean addZutat(Zutat zutat) {
        
        for (int i=0; i<zutaten.length; i++) {
            if(zutaten[i]!=null&&zutaten[i]==zutat) {
                
                return false;
            }
        }
        for (int i=0; i<10; i++) {
            if (zutaten[i]==null) {
                zutaten[i]=zutat;
                break;
            }
        }
        return true;
    }
    
    public boolean removeZutat(Zutat zutat) {
        
        for (int i=0; i<10; i++) {
            if(zutaten[i]!=null&&zutaten[i]==zutat) {
                zutaten[i]=null;
                return true;
            }
        }
        return false;
    }
 
Was du evtl. noch anpassen willst: die "10" taucht da mehrfach in den Schleifen auf. Das sollte man noch ersetzen. Denn 10 kann an vielen Stellen vorkommen und dann soll das Zutaten größer werden ... statt 10 soll morgen 20 Zutaten untergebracht werden können... dann musst Du die richtigen "10"er finden .... daher vermeidet man das.

Kennst Du eine Möglichkeit, die Größe eines Arrays auszulesen?

Und Ich bin zu langsam ... Sehr gut! ... Aber bei removeZutat und der zweiten Schleife auch noch 🙂
 
Noch ein Hinweis: Schau dir auch produzieren() noch mal an. Die Aufgabe verlangt, dass von jeder verfügbaren Zutat, mindestens die geforderte Anzahl vorhanden sein muss, bevor produziert werden kann. Überleg dir mal, was passiert, wenn bei dir eine (oder mehrere) Zutat die nicht die richtige Menge hat.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Im Grunde prüft die If-Abfrage das ganze Array und jedes mal wenn die Abfrage richtig ist, werden die Anweisungen ausgeführt, d.h. wenn bei den ersten 5 Array-Feldern die Abfrage stimmt, werden die Anweisungen ausgeführt und bei den anderen dann nicht. Also müsste im Grunde erst das ganze Array überprüft werden und erst danach die Anweisung durchgeführt werden.
Klappt es wenn ich da eine boolean-Variable einfüge in der Schleife und erst wenn diese auch nach dem letzten Durchlauf true ist, sollen die Veränderungen durchgeführt werden
 
Also müsste im Grunde erst das ganze Array überprüft werden und erst danach die Anweisung durchgeführt werden.
Ja.
Klappt es wenn ich da eine boolean-Variable einfüge in der Schleife und erst wenn diese auch nach dem letzten Durchlauf true ist, sollen die Veränderungen durchgeführt werden
Eher nein. Du musst ja für jede Zutat die Menge ändern und dazu auch das gesamte Array nochmal durchgehen. Die Menge der produzierten Produkte musst du allerdings nur einmal ändern! Aufpassen!

Mach es vom Prinzip, wie in der Methode addZutat(). Erst prüfen, dann machen.
 
Ja.

Eher nein. Du musst ja für jede Zutat die Menge ändern und dazu auch das gesamte Array nochmal durchgehen. Die Menge der produzierten Produkte musst du allerdings nur einmal ändern! Aufpassen!

Mach es vom Prinzip, wie in der Methode addZutat(). Erst prüfen, dann machen.
Ja meinte auch, dass es nach dem kompletten Durchlauf ersetzt werden soll und nicht immer eins prüfen und setzen.
Code:
public boolean produzieren(int anzahl) {
        for (int i=0; i<zutaten.length; i++) {
            if(zutaten[i].getAnzahlVerfuegbarerEinheiten()>=anzahl) {
                return false;
            }
        }
        for (int i=0; i<zutaten.length; i++) {
            
            zutaten[i].setAnzahlVerfuegbarerEinheiten(zutaten[i].getAnzahlVerfuegbarerEinheiten() - anzahl);
        }
        setAnzahlVorhanden(getAnzahlVorhanden() + anzahl);
        return true;
    }
 
Code:
    public boolean addZutat(Zutat zutat) {
     
        for (int i=0; i<zutaten.length; i++) {
            if(zutaten[i]!=null&&zutaten[i]==zutat) {
             
                return false;
            }
        }
        for (int i=0; i<10; i++) {
            if (zutaten[i]==null) {
                zutaten[i]=zutat;
                break;
            }
        }
        return true;
    }
 
    public boolean removeZutat(Zutat zutat) {
     
        for (int i=0; i<10; i++) {
            if(zutaten[i]!=null&&zutaten[i]==zutat) {
                zutaten[i]=null;
                return true;
            }
        }
        return false;
    }

Die Lösung bei #29 war besser. Du solltest den Vergleich unbedingt über den Namen machen! Wenn du die Objekte direkt vergleichst werden die Referenzen verglichen und das kann schief gehen (abhängig davon, was die Testmethode da rein gibt).
 
Das hat keinen Sinn gemacht
Code:
public boolean produzieren(int anzahl) {
        for (int i=0; i<zutaten.length; i++) {
            if(zutaten[i].getAnzahlVerfuegbarerEinheiten()<anzahl) {
                return false;
            }
        }
        for (int i=0; i<zutaten.length; i++) {
            
            zutaten[i].setAnzahlVerfuegbarerEinheiten(zutaten[i].getAnzahlVerfuegbarerEinheiten() - anzahl);
        }
        setAnzahlVorhanden(getAnzahlVorhanden() + anzahl);
        return true;
    }
 
Das hat keinen Sinn gemacht
Code:
public boolean produzieren(int anzahl) {
        for (int i=0; i<zutaten.length; i++) {
            if(zutaten[i].getAnzahlVerfuegbarerEinheiten()<anzahl) {
                return false;
            }
        }
        for (int i=0; i<zutaten.length; i++) {
           
            zutaten[i].setAnzahlVerfuegbarerEinheiten(zutaten[i].getAnzahlVerfuegbarerEinheiten() - anzahl);
        }
        setAnzahlVorhanden(getAnzahlVorhanden() + anzahl);
        return true;
    }

Du hast den fehlerhaften Vergleich ja gefunden. Super!
 
Das hat keinen Sinn gemacht
Code:
public boolean produzieren(int anzahl) {
        for (int i=0; i<zutaten.length; i++) {
            if(zutaten[i].getAnzahlVerfuegbarerEinheiten()<anzahl) {
                return false;
            }
        }
        for (int i=0; i<zutaten.length; i++) {
           
            zutaten[i].setAnzahlVerfuegbarerEinheiten(zutaten[i].getAnzahlVerfuegbarerEinheiten() - anzahl);
        }
        setAnzahlVorhanden(getAnzahlVorhanden() + anzahl);
        return true;
    }

Aber immer dran denken: Da können auch null-Werte drinstehen!
 
Code:
public boolean produzieren(int anzahl) {
        for (int i=0; i<zutaten.length; i++) {
            if(zutaten[i].getAnzahlVerfuegbarerEinheiten()<anzahl) {
                return false;
            }
        }
        for (int i=0; i<zutaten.length; i++) {
            
            zutaten[i].setAnzahlVerfuegbarerEinheiten(zutaten[i].getAnzahlVerfuegbarerEinheiten() - anzahl);
        }
        setAnzahlVorhanden(getAnzahlVorhanden() + anzahl);
        return true;
    }
    
    public boolean addZutat(Zutat zutat) {
        
        for (int i=0; i<zutaten.length; i++) {
            if(zutaten[i]!=null&&zutaten[i].getName().equals(zutat.getName())) {
                
                return false;
            }
        }
        for (int i=0; i<zutaten.length; i++) {
            if (zutaten[i]==null) {
                zutaten[i]=zutat;
                break;
            }
        }
        return true;
    }
    
    public boolean removeZutat(Zutat zutat) {
        
        for (int i=0; i<zutaten.length; i++) {
            if(zutaten[i]!=null&&zutaten[i].getName().equals(zutat.getName())) {
                zutaten[i]=null;
                return true;
            }
        }
        return false;
    }

So siehts jetzt aus, aber der Test liefert bei produzieren bei der ersten IF-Abfrage wieder eine NullPointerException.

Eine andere Frage noch:
Wenn ich die Strings mit equals vergleiche, schlägt mir eclipse contentequals vor. Ist das "besser" bzw. dasselbe?
 
Du solltest den Vergleich unbedingt über den Namen machen! Wenn du die Objekte direkt vergleichst werden die Referenzen verglichen und das kann schief gehen (abhängig davon, was die Testmethode da rein gibt).

Nur noch kurz die Erläuterung dazu:

Java:
Produkt p1 = new Produkt("Foo");
Produkt p2 = p1;
Produkt p3 = new Produkt("Foo");

p1 == p2; // true
p2 == p3; // false

p1.getName().equals(p2.getName()); // true
p2.getName().equals(p3.getName()); // true

Obwohl die beiden Produkte p1 und p3 "Foo" sind wird der Vergleich false ergeben, weil es sich um ein komplett neues Objekt (mit zwar identischen Inhalt) handelt und damit die Referenzen unterschiedlich sind.
 
Zuletzt bearbeitet:

Neue Themen


Zurück
Oben