我们都知道,比较两个对象的是否相同,一般是先通过hashcode方法比较hash值是否相等,如果相同(哈希碰撞)然后通过equals进行比较各个属性值是否相同,如果都相同,那么才是真正的相同。
我们看一个使用retainAll更新OrderItem的方法:
private boolean intersection(boolean flag,
List orderItemVoStatisticsList,
List orderItemVoTemporaryList) {
//1、求交集
List listIntersection = new ArrayList<>(orderItemVoTemporaryList);
listIntersection.retainAll(orderItemVoStatisticsList);
if (!EmptyUtil.isNullOrEmpty(listIntersection)) {
// 交集中的订单项 转map ==> key: dishId value: num
Map dishIdAndNum = listIntersection.stream().collect(
Collectors.toMap(OrderItemVo::getDishId, OrderItemVo::getDishNum));
// 在mysql的订单项中,找到交集中所包含菜品的订单项
List orderItemList = orderItemVoStatisticsList.stream()
// 找到交集中所包含菜品的订单项
.filter(orderItemVo -> dishIdAndNum.containsKey(orderItemVo.getDishId()))
// 封装为OrderItem
.map(orderItemVo -> OrderItem.builder()
.id(orderItemVo.getId())
//mysql中菜品数量 + redis中对应菜品数量
.dishNum(orderItemVo.getDishNum() + dishIdAndNum.get(orderItemVo.getDishId()))
.build())
// 收集到批量集合中 进行修改
.collect(Collectors.toList());
flag = orderItemService.updateBatchById(orderItemList);
}
return flag;
}
这里使用retainAll方法去取交集
那么它是怎么判断两个对象是否相同的呢?就算我redis购物车订单项和mysql数据库订单项的点的菜是一样的,但是可能菜的数量,菜的口味还不一样呢,甚至还有其他属性不同等等,那么应该怎么实现呢?
/**
* @ClassName OrderItemVo.java
* @Description 订单项
*/
@Data
@NoArgsConstructor
public class OrderItemVo extends BasicVo {
private static final long serialVersionUID = 1L;
@Builder
public OrderItemVo(Long id, Long productOrderNo, BigDecimal memberDiscount, BigDecimal discountAmount,
Long dishId, String dishName, String categoryId, BigDecimal price, BigDecimal reducePrice,
Long dishNum,String dishFlavor){
super(id);
this.productOrderNo=productOrderNo;
this.memberDiscount=memberDiscount;
this.discountAmount=discountAmount;
this.dishId=dishId;
this.dishName=dishName;
this.categoryId=categoryId;
this.price=price;
this.reducePrice=reducePrice;
this.dishNum=dishNum;
this.dishFlavor = dishFlavor;
}
@ApiModelProperty(value = "业务系统订单号【分表字段】")
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long productOrderNo;
@ApiModelProperty(value = "会员折扣")
private BigDecimal memberDiscount;
@ApiModelProperty(value = "优惠金额")
private BigDecimal discountAmount;
@ApiModelProperty(value = "菜品ID")
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long dishId;
@ApiModelProperty(value = "菜品名称")
private String dishName;
@ApiModelProperty(value = "菜品分类id")
@JsonFormat(shape = JsonFormat.Shape.STRING)
private String categoryId;
@ApiModelProperty(value = "菜品价格")
private BigDecimal price;
@ApiModelProperty(value = "菜品优惠价格")
private BigDecimal reducePrice;
@ApiModelProperty(value = "菜品数量")
private Long dishNum;
@ApiModelProperty(value = "菜品附件信息")
private FileVo fileVo;
@ApiModelProperty(value = "菜品口味")
private String dishFlavor;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OrderItemVo that = (OrderItemVo) o;
return dishId.equals(that.dishId);
}
@Override
public int hashCode() {
return Objects.hash(dishId);
}
}
很明显,这里重写了hashCode和equals方法,而且很巧妙的是他只是对dishId进行了hash运算和equals比较,这样只要是相同的菜品,那么我就可以取其交集,进行之后的逻辑操作!
所以当我们使用retainAll对两个集合取交集时,要确定我们集合中的泛型是否重写了针对指定属性重写了hash和equals方法,否则将会取交失败。
boolean batchRemove(Collection> c, boolean complement,
final int from, final int end) {
//集合C不能为空
Objects.requireNonNull(c);
//定义一个数组
final Object[] es = elementData;
int r;
// Optimize for initial run of survivors
for (r = from;; r++) {
if (r == end)
return false;
if (c.contains(es[r]) != complement)
break;
}
int w = r++;
try {
for (Object e; r < end; r++)
if (c.contains(e = es[r]) == complement)
es[w++] = e;
} catch (Throwable ex) {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
System.arraycopy(es, r, es, w, end - r);
w += end - r;
throw ex;
} finally {
modCount += end - w;
shiftTailOverGap(es, w, end);
}
return true;
}
这段代码实现批量删除,即从集合C中删除所有在数组元素[from, end)范围内的元素(根据布尔值complement参数决定是删除还是保留这些元素)这里第true。