【问题标题】:Increasing value of an object if it's already in a map如果对象已经在地图中,则增加对象的值
【发布时间】:2022-01-24 14:52:49
【问题描述】:

每次将产品添加到购物篮时,如果它已经在地图篮中,它应该将其价值增加 1。但由于某种原因它不会。是因为每次我将产品添加到地图时,我都会创建新的购买?我想不通。

public void add(String product, int price) {
        Purchases buy =  new Purchases(product, 1, price);
        if(!basket.containsKey(product)) {
            
            basket.put(product, buy);
        } else {
            
            buy.increaseAmount();
        }

/

public void increaseAmount() {
        this.amount+= 1;
    }

/

public class Main {

    
    public static void main(String[] args) {
        
        
           ShoppingBasket basket = new ShoppingBasket();
           basket.add("milk", 3);
           basket.print();
           System.out.println("basket price: " + basket.price() +"\n");

           basket.add("buttermilk", 2);
           basket.print();
           System.out.println("basket price: " + basket.price() +"\n");

           basket.add("milk", 3);
           basket.print();
           System.out.println("basket price: " + basket.price() +"\n");

           basket.add("milk", 3);
           basket.print();
           System.out.println("basket price: " + basket.price() +"\n");
               
            
        }
    }

/

import java.util.HashMap;
import java.util.Map;

public class ShoppingBasket {
    private Map<String,Purchases> basket;
    
    
    public ShoppingBasket() {
        this.basket = new HashMap<String,Purchases>();
    }
    
    public void add(String product, int price) {
        Purchases buy =  new Purchases(product, 1, price);
        if(!basket.containsKey(product)) {
            
            basket.put(product, buy);
        } else {
            
            buy.increaseAmount();
        }
        
    
    }
    public int price() {
        int price = 0;
        for(Purchases item : basket.values()) {
            price += item.price();
        }
        return price;
    }
    
    public void print() {
        Map<String, Integer> test = new HashMap<String,Integer>();
        for(Purchases item : basket.values()) {
                test.put(item.product(), item.amount());
        }
        for(String key : test.keySet()) {
            Integer value = test.get(key);
            
            String complete = key + ": " + value;
            System.out.println(complete);
            
        }
    }
    
    

    }

/

public class Purchases {
    private String product;
    private int amount;
    private int unitPrice;

    public Purchases(String product,int amount, int unitPrice) {
        this.product = product;
        this.amount = amount;
        this.unitPrice = unitPrice;
    }
    
    public int price() {
        return this.amount * this.unitPrice;
    }
    public void increaseAmount() {
        this.amount+= 1;
    }
    
    public String toString() {
        return "" + this.amount;
    }
    
    public int amount() {
        return this.amount;
    }
    
    public String product() {
        return this.product;
    }
}

【问题讨论】:

  • buy.increaseAmount() 增加新创建的购买对象的数量,但不是地图内的那个。实际上,如果地图中已有购买对象,则不应创建购买对象。

标签: java hashmap


【解决方案1】:

这是因为您在新的Purchases 对象中增加了amount,而该对象不在地图中。


我们来做代码分析:

[地图状态] EMPTY

您在地图中放置了一个带有product 名称/键"milk"Purchases 对象:

public void add(String product, int price) {
   Purchases buy =  new Purchases(product, 1, price);

   if(!basket.containsKey(product)) {     
      // Executed       
      basket.put(product, buy);
   } else {       
      buy.increaseAmount();
   }
}

您可能知道执行 if 块中的代码 - 将 buy 内的对象添加到地图中。

[地图状态] { "milk", PurchasesObject1 }

现在您再次尝试将product 的/键值为"milk"NEW Purchases 对象再次放入地图中。你可能知道,else块会被执行,因为Purchases的key为"milk"的对象已经存在于map中了。

else 块中发生的情况是,您增加了您刚刚在方法中创建的 NEW 本地对象amount 的值,该方法甚至根本不在地图中,所以一旦add()方法执行完毕,你创建的对象就变成了垃圾,需要被垃圾回收器回收。


解决方案?

当然。只需使用相同的键检索对象并对其执行您想要的操作即可。

public void add(String product, int price) {
   Purchases buy =  new Purchases(product, 1, price);

   if(!basket.containsKey(product)) {     
      // Executed       
      basket.put(product, buy);
   } else {       
      basket.get(product).increaseAmount();
   }
}

【讨论】:

    【解决方案2】:

    Purchases buy = new Purchases(product, 1, price);

    看到new了吗?你在这里制作了一个 new 对象,因此得名。然后,您增加这个新对象的产品计数,并立即将引用这个新对象的唯一变量(您的 buy 变量)扔进垃圾箱,因为当方法结束时所有局部变量都会发生这种情况:变量消失.这样一来,没有任何东西指向这个全新的 Purchases 实例,因此它最终会被垃圾回收。

    您想查询之前制作并存储在该地图中的实际对象,然后在其上增加产品计数。

    在您的代码中,无论发生什么情况,您都会创建一个新的 Purchases 实例,然后仅当该字符串不在您的映射中时才将给定的字符串映射到这个新创建的采购对象。这不好。只有在地图中还没有新的购买实例时,您才想创建一个新的购买实例,否则您想获取现有的购买实例。

    你可以这样做:

    Purchases buy;
    if(!basket.containsKey(product)) {
      basket.put(product, buy = new Purchases(product, 1, price));
    } else {
      basket.get(product).increaseAmount();
    }
    

    但是如果这是一个并发的 hashmap,这是低效的,“丑陋的”(有点难以维护),并且完全被破坏了。更好的是先行动后检查:

    basket
      .computeIfAbsent(product, k -> new Purchases(product, 0, price))
      .increaseAmount();
    

    这段代码正如它所说的那样:它将计算必要的值,但前提是没有键/值映射。因此,如果 product 在地图中,您只需获取与之关联的 Purchases 实例,我们就会立即转到 .increaseAmount()。但如果不是,则执行代码new Purchases(product, 0, price),并将解析为的任何内容用作值(因此,它就像.put(product, new Purchases(...)),除了新部分仅在该项目不在地图中时运行。那里有一个k -&gt;,因为 [A] 它是一个闭包,它是发送到computeIfAbsent 方法的代码,并且仅在需要时才实际运行,并且 [B] 你得到传递的密钥。在这里,不需要,你已经有了这个(变量product),但你可以想象你可能调用了basket.computeIfAbsent(some.complex().calculation(), ....,这就是它存在的原因。

    然后,无论您得到什么,您都可以致电increaseAmount()。因此,为什么这段代码以 0 开头:因为它会在之后立即递增到 1。

    【讨论】:

      【解决方案3】:

      如果密钥已经存在,代码不会将购买添加到地图中,请在其他部分添加 map.put

      public void add(String product, int price) {      
              Purchases buy =  new Purchases(product, 1, price);         
              if(!basket.containsKey(product)) {                    
                  basket.put(product, buy);    
              } else {              
                  buy.increaseAmount();      
                  basket.put(product, buy);        
              }    
      }
      

      【讨论】:

        【解决方案4】:

        在您的 else black 中,您需要从地图中检索 Purchase 对象。然后在检索到的对象上调用increaseAmount

            public void add(String product, int price) {
                Purchases buy =  new Purchases(product, 1, price);
                if(!basket.containsKey(product)) {   
                    basket.put(product, buy);
                } else {
                    buy = basket.get(product);  <--retrieve it 
                    buy.increaseAmount();      <--increment amount
                }
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-05-04
          • 2021-06-04
          • 2012-09-12
          • 2019-12-23
          • 1970-01-01
          • 1970-01-01
          • 2017-11-26
          相关资源
          最近更新 更多