更新集合中的项目

时间:2018-02-15 10:58:52

标签: java performance collections

我在Java中有Collection个对象,我需要获取一个特定的项目才能更新它的属性。我可以使用streamfilter获取该项目并进行更新,或者我可以使用.remove().add()来替换旧对象。

我的问题是,哪一个会更好地表现性能,一般来说每种方法的优点和缺点是什么。

e.g

public class Car
{
    private Integer id //unique;
    private String brand;
    private Float price;

    Car(Integer id, String brand, Float price)
    {
        this.id = id;
        this.brand = brand;
        this.price = price;
    }

    public Integer getId()
    {
        return id;
    }

    public void setId(Integer id)
    {
        this.id = id;
    }

    public String getBrand()
    {
        return brand;
    }

    public void setBrand(String brand)
    {
        this.brand = brand;
    }

    public Float getPrice()
    {
        return price;
    }

    public void setPrice(Float price)
    {
        this.price = price;
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o)
        {
            return true;
        }
        if (o == null)
        {
            return false;
        }

        Car car = (Car) o;

        return id != null && id.equals(car.getId());
    }

    @Override
    public int hashCode()
    {
        return id != null ? id.hashCode() : 0;
    }

}


public static void main(String[] args)
    {
        Collection<Car> cars = new ArrayList<>();

        cars.add(new Car(1, "Ford", (float)10000));
        cars.add(new Car(2, "Fiat", (float)15000));
        cars.add(new Car(2, "BMW", (float)20000));

        //Method 1
        Car updateCar = new Car(2, "Fiat", (float)35000);
        Car newCar =  cars.stream().filter(c -> c.getId().equals(updateCar.getId())).collect(toList()).get(0);
        newCar.setPrice(updateCar.getPrice());

        //Method 2
        Car updateCar = new Car(2, "Fiat", (float)15000);
        cars.remove(updateCar);
        updateCar.setPrice((float)35000);
        cars.add(updateCar);
    }

5 个答案:

答案 0 :(得分:2)

您正在以错误的方式看待它:在考虑性能时,您的进入点应该是时间复杂性。然后,您可以深入研究实现细节。

在您的情况下,两种方法都在O(n)中运行。

如果性能非常重要,请转到O(1)算法,例如使用HashMap<Integer, Car

答案 1 :(得分:0)

解决方案3:使用Map按ID存储每辆车。这是ID的目标,正确使用它。

因此更新只需要map.get(id).setPrice(newprice)。

另一个注意事项:当你想获得一个潜在元素时,不要使用collect()。 对于并行方法,Streams有findFirst()或findAny()。 所以

Car filtered = list.stream().filter(predicate).findFirst().get()

会有更好的表现。

答案 2 :(得分:0)

如果ID不是唯一的,那么您提出的方法1将不准确。例如,如果您尝试更换BMW,您将更改菲亚特的那辆,因为它们具有相同的ID。

无论如何,除非您的对象是不可变的,或者您使用了Set

,否则最高效的方式既不会过滤也不会删除/插入,而是更新

如果你真的关心性能,你应该使用唯一的ID和Map,而不仅仅是Collection

答案 3 :(得分:0)

两者都不会产生性能,因为时间复杂度将为O(n)。如果你真的从性能的角度来看,请使用HashMap put和get。它总是给O(1)

示例:

地图放置和获取时间复杂度总是O(1)

Map<Integer,Car> carsMap = new HashMap<Integer,Car>();
   carsMap.put(1, new Car(1, "Ford", (float) 10000));
   carsMap.put(2, new Car(2, "Fiat", (float) 15000));

   // Update Value of Car
   Car newCar = carsMap.get(2);
   newCar.setPrice((float) 35000);
   carsMap.put(2, newCar);

答案 4 :(得分:0)

你的两种方法在性能方面都没有多大意义

方法1

    Car updateCar = new Car(2, "Fiat", (float)35000); // unnecessary object construction
    Car newCar =  cars.stream()
      .filter(c -> c.getId().equals(updateCar.getId()))
      .collect(toList()) // unnecessary List creation
      .get(0); // just to get the first element
    newCar.setPrice(updateCar.getPrice()); // to perform an action on it

直接的解决方案是

    Integer idToUpdate = 2;
    float newPrice = 35000;
    cars.stream()
        .filter(c -> idToUpdate.equals(c.getId()))
        .forEach(car -> car.setPrice(newPrice));

方法2

    Car updateCar = new Car(2, "Fiat", (float)15000); // unnecessary use of old values
    cars.remove(updateCar);
    updateCar.setPrice((float)35000);// just to update the property
    cars.add(updateCar);

由于Car的相等性仅基于ID,因此无需使用旧属性初始化新的Car实例。

请注意,由于您未指定集合类型,因此我们不知道它是否可能包含重复项。所以直截了当的变体是

    Car updateCar = new Car(2, "Fiat", 35000);        
    do {} while(cars.remove(updateCar));
    cars.add(updateCar);

或,以确保出现的次数不会改变:

    Car updateCar = new Car(2, "Fiat", 35000);
    int num = 0;
    while(cars.remove(updateCar)) num++;
    cars.addAll(Collections.nCopies(num, updateCar));

但这可能仍会改变集合元素的顺序(如果特定集合类型有订单)。

显然,第一个变体更简单并且保留了源集合的属性,这比微小的性能差异更重要。除非集合是Set,否则这两个操作都意味着线性开销,这可以通过使用从id到实例的映射来避免。