关键字
代码、代码片段、集合、交集、差集、补集
场景
很多人写Java代码时,都比较喜欢用List集合,而不是用Set集合,虽然应该Set集合的不重复特性更符合他的业务场景。虽然教科书式的Java教程叫我们重写equals、hashCode方法,但实际上有些人却不想这么干。
下面的代码片段,特点在于使用自定义的java.util.function.BiPredicate
(jdk8+才有这个类)接口来为两个java.util.List
计算交集、补集(差集)。BiPredicate
接口可以自己实现test
方法逻辑,返回boolean
,以判定List中的元素是否相同。
上代码
/**
* 取{@code firstList}参数与{@code secondList}参数的交集
*
* <p>通过传入{@link BiPredicate}接口的实现,自定义判断 {@code firstList}与{@code secondList}的哪些元素相同。
* 效果类似于实现了{@code T}的{@code equals}方法,但此方法的优点是不要求你这么做,可以让你通过{@link BiPredicate}接口无侵入式的自定义{@code equals}逻辑。</p>
* <p>假设{@code firstList}中的元素为[1,2,3],{@code secondList}中的元素为[2,3,4],则返回{@code firstList}中的[2,3]</p>
*
* @param firstList 第一个集合
* @param secondList 第二个集合
* @param equalPredicate 判断两个元素是否相同
* @return 返回 {@link ArrayList}实例,其中的元素是{@code firstList}参数与{@code secondList}的交集。注意,{@link ArrayList}实例中的元素引用来源于{@code firstList}而不是{@code secondList}
* @throws NullPointerException 如果<code>firstList</code>、<code>secondList</code>、<code>equalPredicate</code>参数为null
* @author laozhu
*/
public static <T> ArrayList<T> retain(List<T> firstList, List<T> secondList, BiPredicate<T,T> equalPredicate){
Objects.requireNonNull(firstList);
Objects.requireNonNull(secondList);
Objects.requireNonNull(equalPredicate);
ArrayList<T> resultList = new ArrayList<>();
for(int i = 0; i < firstList.size(); i++){
for(int j = 0; j < secondList.size(); j++){
if(equalPredicate.test(firstList.get(i),secondList.get(j))){
//相同元素
resultList.add(firstList.get(i));
//break能够防止secondList中有重复的元素,导致resultList中添加了两个相同的firstList中的元素
break;
}
}
}
return resultList;
}
/**
* 取{@code firstList}参数与{@code secondList}的补集(又叫差集)
*
* <p>通过传入{@link BiPredicate}接口的实现,自定义判断 {@code firstList}与{@code secondList}的哪些元素相同。
* 效果类似于实现了{@code T}的{@code equals}方法,但此方法的优点是不要求你这么做,可以让你通过{@link BiPredicate}接口无侵入式的自定义{@code equals}逻辑。</p>
* <p>假设{@code firstList}中的元素为[1,2,3],{@code secondList}中的元素为[2,3,4],则返回{@code firstList}中的[1]</p>
*
* @param firstList 第一个集合
* @param secondList 第二个集合
* @param equalPredicate 判断两个元素是否相同
* @return 返回 {@link ArrayList}实例,其中的元素是{@code firstList}参数与{@code secondList}的补集(又叫差集)。注意,{@link ArrayList}实例中的元素引用来源于{@code firstList}而不是{@code secondList}
* @throws NullPointerException 如果<code>firstList</code>、<code>secondList</code>、<code>equalPredicate</code>参数为null
* @author laozhu
*/
public static <T> List<T> diff(List<T> firstList, List<T> secondList, BiPredicate<T,T> equalPredicate){
Objects.requireNonNull(firstList);
Objects.requireNonNull(secondList);
Objects.requireNonNull(equalPredicate);
ArrayList<T> resultList = new ArrayList<>();
for(int i = 0; i < firstList.size(); i++){
boolean hasEqualElementInSecondList = false;
for(int j = 0; j < secondList.size(); j++){
if(equalPredicate.test(firstList.get(i),secondList.get(j))){
//相同元素
hasEqualElementInSecondList = true;
break;
}
}
if(!hasEqualElementInSecondList){
resultList.add(firstList.get(i));
}
}
return resultList;
}
调用示例
交集
代码:
public class HelloWorld {
public static void main(String[] args) {
Student s1 = new Student("100","zhangsan");
Student s2 = new Student("101","zhangsan");
Student s3 = new Student("102","zhangsan");
Student s4 = new Student("103","zhangsan");
List<Student> list1 = Arrays.asList(s1,s2);
List<Student> list2 = Arrays.asList(s2,s3,s4);
List result = SetUtil.retain(list1,list2,(a,b)->a.getSid().equals(b.getSid()));
System.out.println("交集:");
System.out.println(result);
}
}
打印结果:
交集:
[Student{sid='101', name='zhangsan'}]
补集(差集)
代码:
public class HelloWorld {
public static void main(String[] args) {
Student s1 = new Student("100","zhangsan");
Student s2 = new Student("101","zhangsan");
Student s3 = new Student("102","zhangsan");
Student s4 = new Student("103","zhangsan");
List<Student> list1 = Arrays.asList(s1,s2);
List<Student> list2 = Arrays.asList(s2,s3,s4);
List result = SetUtil.diff(list1,list2,(a,b)->a.getSid().equals(b.getSid()));
System.out.println("补集(差集):");
System.out.println(result);
}
}
打印结果:
补集(差集):
[Student{sid='100', name='zhangsan'}]