1:需求
定时从其他微服务同步数据,保存到本地数据库。数据量大,如果每条数据每次都更新,则比较慢。因此需要“远程拉取数据list(A)”与"本地数据查询的list(B)"依据某些字段比较,然后获取A=B、A>B、B=A、B>A (谁在前stream是以谁为基础)
2:数据准备
两个对象+两个list。。模拟从远程获取的数据+本地库查找的数据
@Data
public class Dish {
private String name; //菜的名称
private Boolean vegetaian; //是否为素
private Integer calories; //卡路里
private Type type; //类型(肉 鱼 其他)
public Dish() { }
public Dish(String name, Boolean vegetaian, Integer calories, Type type) {
this.name = name;
this.vegetaian = vegetaian;
this.calories = calories;
this.type = type;
}
public enum Type {MEAT, FISH, OTHER} //肉 鱼 其他
}
@Data
public class UmDish {
private String umname; //菜的名称
private Boolean umvegetaian; //是否为素
private Integer umcalories; //卡路里
private UmType umtype; //类型(肉 鱼 其他)
public UmDish() {
}
public UmDish(String umname, Boolean umvegetaian, Integer umcalories, UmType umtype) {
this.umname = umname;
this.umvegetaian = umvegetaian;
this.umcalories = umcalories;
this.umtype = umtype;
}
public enum UmType {MEAT, FISH, OTHER} //肉 鱼 其他
}
//数据准备
public static List<UmDish> getUmDish1List() {
return Arrays.asList(
new UmDish("pork", false, 800, UmDish.UmType.MEAT),
new UmDish("beef-1", false, 700, UmDish.UmType.MEAT),
new UmDish("chicken-1", false, 400, UmDish.UmType.MEAT),
new UmDish("french fries", true, 530, UmDish.UmType.OTHER),
new UmDish("rice", true, 350, UmDish.UmType.OTHER),
new UmDish("season fruit", true, 120, UmDish.UmType.OTHER),
new UmDish("pizza", true, 550, UmDish.UmType.OTHER),
new UmDish("prawns", false, 300, UmDish.UmType.FISH),
new UmDish("salmon", false, 450, UmDish.UmType.FISH)
);
}
//数据准备
public static List<Dish> getDish1List() {
return Arrays.asList(
new Dish("pork", false, 800, Dish.Type.MEAT),
new Dish("pork-1", false, 800, Dish.Type.MEAT),
new Dish("beef", false, 700, Dish.Type.MEAT),
new Dish("chicken", false, 400, Dish.Type.MEAT),
new Dish("french fries", true, 530, Dish.Type.OTHER),
new Dish("rice", true, 350, Dish.Type.OTHER),
new Dish("season fruit", true, 120, Dish.Type.OTHER),
new Dish("pizza", true, 550, Dish.Type.OTHER),
new Dish("prawns", false, 300, Dish.Type.FISH),
new Dish("salmon", false, 450, Dish.Type.FISH)
);
}
3:解决方案
略。。。。。。
缺点:如果好多种list需要比较,则要针对写不同的比较策略,代码长,不易阅读,而且修改不灵活(比如:获取A=B、A!=B、A>B、A<B 是非常麻烦的)
方法:
/**
* 过滤两个list<Bean>数据的策略(bean对象可以不同)
*
* @param otherList 被比较的List<bean>
* @param otherFunction 被比较的Function(目的是为了组装key)
* @param thisFunction 调用此方法方的Function(目的是为了组装key)
* @return
*/
public static <E, M, V> Predicate<E> distinctByOtherList(List<M> otherList, Function<M, V> otherFunction, Function<E, V> thisFunction) {
Set<V> otherKeySet = otherList.stream().map(otherFunction).collect(Collectors.toSet());
return e -> Boolean.TRUE.equals(otherKeySet.contains(thisFunction.apply(e)));
}
使用:
@Test
public void testDistinct2List() {
List<Dish> dish1List = DishList.getDish1List();
List<UmDish> umDish1List = DishList.getUmDish1List();
// umDishFunction(组装key)
Function<UmDish, String> umDishFunction = umDish -> umDish.getUmtype() + "-" + umDish.getUmname();
// dishFunction(组装key)
Function<Dish, String> function = umDish -> umDish.getType() + "-" + umDish.getName();
// A=B
List<Dish> collect1 = dish1List.stream().filter(distinctByOtherList(umDish1List, umDishFunction, function)).collect(Collectors.toList());
// A>B
List<Dish> collect2 = dish1List.stream().filter(distinctByOtherList(umDish1List, umDishFunction, function).negate()).collect(Collectors.toList());
// B=A
List<UmDish> collect3 = umDish1List.stream().filter(distinctByOtherList(dish1List, function, umDishFunction)).collect(Collectors.toList());
// B>A
List<UmDish> collect4 = umDish1List.stream().filter(distinctByOtherList(dish1List, function, umDishFunction).negate()).collect(Collectors.toList());
// A=B的key(依据此key也可以对umDish1List、dish1List 过滤)
Set<String> collect5 = dish1List.stream().filter(distinctByOtherList(umDish1List, umDishFunction, function)).map(function).collect(Collectors.toSet());
}