Erhöhen eines Values als Integer bei gleichen Keys in HashMap

JuriW

Aktives Mitglied
Hallo,
Ich habe Items, die ich gerne einer HashMap hinzufügen würde mit dem Item als Key und der Anzahl als Value. Falls ein Item öfter vorkommt soll die Anzahl um die neue Anzahl erhöht werden. Um es euch zu verdeutlichen ist hier mein Code:

Java:
import java.util.*;

public class Playground {

    private static HashMap<Item, Integer> produktMap = new HashMap<>();
   
    public static void main(String[] args) {

        Item i1 = new Item("Foo");
        Item i2 = new Item("Bar");
        Item i3 = new Item("Baz");
        Item i4 = new Item("Foo");

        addEntryToHashMap(i1,2);
        addEntryToHashMap(i2,3);
        addEntryToHashMap(i3,1);
        addEntryToHashMap(i4,3);

        System.out.println(produktMap);
    }

    public static void addEntryToHashMap(Item i, int anzahl) {

        for (HashMap.Entry<Item, Integer> entry : produktMap.entrySet()) {
            if (produktMap.containsKey(i)) {
                 entry.setValue(entry.getValue() + anzahl);
            } else {
                 produktMap.put(i, anzahl);
            }
        }
    }
}

Ich bekomme leider nur {} als Output. Am Ende sollen die Items mit Ihrer Anzahl erscheinen, Foo soll dabei mit 5 (nämlich 2 vom alten + 3 vom neuen Hinzufügen) ausgegeben werden.

Wo habe ich meinen Denkfehler?
 
Zu Beginn ist die Map leer, d. h. Du iterierst über eine leere Map -> das if wird niemals erreicht. Außerdem darfst Du eine Map, über die Du iterierst, nicht direkt manipulieren.

Nachtrag, um die Sache abzukürzen:
Java:
if (produktMap.containsKey(i)) {
    produktMap.put(i, produktMap.get(i) + anzahl);
} else {
    produktMap.put(i, anzahl);
}
oder beispielsweise auch
Java:
int vorhanden = produktMap.containsKey(i) ? produktMap.get(i) : 0;
produktMap.put(i, vorhanden + anzahl);
 
Zuletzt bearbeitet:
Meinst du containsKey() ? (Bei contains() wird mir ein Compilerfehler ausgespuckt) Falls ich containsKey(i) benutze, bekomme ich als Ergebnis

Code:
{Bar=3, Foo=3, Foo=2, Baz=1}

Anstatt Foo=5
 
Leider doch. Hier ist der Code beider Klassen:

Item:
Java:
public class Item {

    private String name;

    public Item(String name){
        this.name = name;
     }

    public String toString(){
        return name;
    }
}

Playground:
Java:
import java.util.*;

public class Playground {

    private static HashMap<Item, Integer> produktMap = new HashMap<>();

    public static void main(String[] args) {

        Item i1 = new Item("Foo");
        Item i2 = new Item("Bar");
        Item i3 = new Item("Baz");
        Item i4 = new Item("Foo");

        addEntryToHashMap(i1, 2);
        addEntryToHashMap(i2, 3);
        addEntryToHashMap(i3, 1);
        addEntryToHashMap(i4, 3);

        System.out.println(produktMap);
    }

    public static void addEntryToHashMap(Item i, int anzahl) {

        if (produktMap.containsKey(i)) {
            produktMap.put(i, produktMap.get(i) + anzahl);
        } else {
            produktMap.put(i, anzahl);
        }
    }
}
 
Geht im übrigen auch als Einzeiler mit Java 8:
Java:
public static void addEntryToHashMap(Item item, int amount) {
    productMap.merge(item, amount, Integer::sum);
}
Item sollte aber equals() und hashcode() so überschreiben, dass 2 Items als gleich gelten, wenn ihr name gleich ist.
 
Okay, danke für eure Antworten. Aber das ist mir gerade zu hoch. ^^
Nach ein bisschen Internetrecherche hab ich es aber so hinbekommen:

Und mit hashCode() hab ich leider noch nie gearbeitet.

Java:
    @Override
    public boolean equals(Object obj) {
        if (obj == null) return false;
        if (!(obj instanceof Item))
            return false;
        if (obj == this)
            return true;
        return this.getName() == ((Item) obj).getName();
    }

    @Override
    public int hashCode(){
        return 1;
    }

Ist equals() richtig überschrieben?

Ich habe bei hashCode() 1 einfach mal "auf gut glück" als Wert für return angegeben.
Der Output ist nun richtig. Kann mir aber jemand sagen wieso? equals() versteh ich, aber hashCode() ist mir zu hoch.
 
Ist equals() richtig überschrieben?
Nein, Objekte vergleicht man mit equals (Achtung: null muss separat behandelt werden).

Für den Hashcode gibt es keine exakte Vorschrift (außer, dass bei zwei Objekten, die "equals"-sind, der gleiche Hashcode rauskommen muss). Er sollte für verschiedene Objekte aber schon möglichst unterschiedlich sein. Du kannst dazu die hashCode-Methode der Objekte verwenden, die in Deinem Item vorhanden sind. Wenn Du noch int-Werte hast, kannst Du diese multiplizieren und addieren.
 
Java:
    @Override
    public boolean equals(Object obj) {
        if (obj == null || obj == this || !(obj instanceof Item)) {
            return obj == this;
        }
        Item itm = (Item) obj;
        return name.equals(itm.name); // setzt voraus, dass name != null
    }
    @Override
    public int hashCode() {
        return name.hashCode();
    }
 
Mit entsprechender null-Behandlung:

Java:
    @Override
    public boolean equals(Object obj) {
        if (obj == null || obj == this || !(obj instanceof Item)) {
            return obj == this;
        }
        Item that = (Item) obj;
        return Objects.equals(this.name, that.name);
    }
    @Override
    public int hashCode() {
        return Objects.hashCode(name);
    }
 

Zurück
Oben