1 起因
在我们日常的业务工作处理中, 经常会遇到需要对两个数组进行比较的操作
例如, 现在有英语与数学两个课外班, 我们需要对这两个班的学生进行如下的统计分析:
- 所有参加了课外班的学生
- 同时参加了英语与数学两个课外班的学生
- 只参加了一门课外班的学生
- 只参加了英语课外班的学生
2 解决方案
其实上面的例子分别对应了两个数组的关系: 并集/交集/交集的补集/差集
我们可以用三种方式进行实现: 原生ArrayList方法/stream/CollectionUtils
下面我将按照统计分析的要求, 同时列出它们的代码, 首先我们默认两个数组为:
List<Student> math = new ArrayList<>();
List<Student> english = new ArrayList<>();
2.1 并集(所有参加了课外班的学生)
// 原生方法
math.removeAll(english);
math.addAll(english);
//stream
// 关于distinct方法在笔者的Java数组去重文章中有
math.addAll(english);
List<Student> result = math.stream().distinct().collect(Collectors.toList());
// CollectionUtils
List<Student> result = (List<Student>) CollectionUtils.union(math, english);
2.2 交集(同时参加了英语与数学两个课外班的学生)
// 原生方法
math.retainAll(english);
//stream
List<Student> result = math.stream().filter(english::contains).collect(Collectors.toList());
// CollectionUtils
List<Student> result = (List<Student>) CollectionUtils.intersection(math, english);
2.3 交集的补集(只参加了一门课外班的学生)
// 原生方法
// 暂时没想出合适的, 先用最蠢的方法
List<Student> result = new ArrayList<>();
for (Student student : math) {
if (english.contains(student)) {
continue;
}
result.add(student);
}
for (Student student : english) {
if (math.contains(student)) {
continue;
}
result.add(student);
}
//stream
List<Student> temp = new ArrayList<>(math);
temp.addAll(english);
List<Student> result = temp.stream().distinct().collect(Collectors.toList());
result.removeAll(math.retainAll(english))
// CollectionUtils
List<Student> result = (List<Student>) CollectionUtils.disjunction(math, english);
2.4 差集(只参加了英语课外班的学生)
// 原生方法
english.removeAll(math)
//stream
List<Student> result = english.stream().filter(student -> !math.contains(student)).collect(Collectors.toList());
// CollectionUtils
List<Student> result = (List<Student>) CollectionUtils.subtract(math, english);
3 总结
总体上来看
原生方法的逻辑最为清晰, 但对补集的处理非常困难, 而且每次操作都影响了初始数组(当然可以通过重构原则来处理这个问题, 例如补集中stream的temp数组)
stream操作简单明了, 偶尔需要结合原生方法
CollectionUtils都拥有对应的方法, 可直接调用, 唯一的缺点是返回结果为Collection并非List, 需要强制转换类型(只要是我讨厌idea里警告的波浪线)