我在Java中有Collection
个对象,我需要获取一个特定的项目才能更新它的属性。我可以使用stream
和filter
获取该项目并进行更新,或者我可以使用.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);
}
答案 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)
你的两种方法在性能方面都没有多大意义
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));
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到实例的映射来避免。