1 Maven依赖

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

2 ListUtil实现集合的异或功能

  • 集合A(1,2,3)异或 集合B(2,3,4)等于 (1,4)
@Test
public void test1() {
List<Integer> listA = new ArrayList<>();
listA.add(1);
listA.add(2);
listA.add(3); List<Integer> listB = new ArrayList<>();
listB.add(2);
listB.add(3);
listB.add(4); long start = System.currentTimeMillis();
List<Integer> sub1 = ListUtils.subtract(listA, listB); // list1与list2的差集
List<Integer> sub2 = ListUtils.subtract(listB, listA); // list2与list1的差集
List<Integer> union = ListUtils.union(sub1, sub2); // sub1与sub2的并集
long diff = System.currentTimeMillis() - start;
log.info("sub1:{}", sub1); // sub1:[1]
log.info("sub2:{}",sub2); // sub2:[4]
log.info("runtime:{}ms,unionList:{}", diff, union);// runtime:5ms, unionList:[1, 4]
}

3 ListUtil源码

  • ListUtils类
public class ListUtils {
// 依赖HashBag类
public static <E> List<E> subtract(final List<E> list1, final List<? extends E> list2) {
final ArrayList<E> result = new ArrayList<E>();
// 涉及HashBag,下面进行讲解
final HashBag<E> bag = new HashBag<E>(list2);
for (final E e : list1) {
if (!bag.remove(e, 1)) {
result.add(e);
}
}
return result;
} // List的addAll功能
public static <E> List<E> union(final List<? extends E> list1, final List<? extends E> list2) {
final ArrayList<E> result = new ArrayList<E>(list1);
result.addAll(list2);
return result;
}
}

4 Bag接口:背包

  • 从出发点(Bag接口)去思考(HashBag类)具体实现中操作的意思
  • 以一个实际生活的例子做解释:一个放球的背包
public interface Bag<E> extends Collection<E> {
// 当object为"红",背包中放了多少红球
int getCount(Object object);
// 当object为"蓝",往背包放一个蓝球
boolean add(E object);
// 当object为"蓝",往背包放nCopies个蓝球
boolean add(E object, int nCopies);
// 当object为"红",把所有红球从背包中取出
boolean remove(Object object);
// 当object为"红",把nCopies个红球从背包中取出
boolean remove(Object object, int nCopies);
// 背包中有哪几种球:如:1个红 2个蓝 -> 红 蓝
Set<E> uniqueSet();
// 总共多少球
int size();
// ...省略一些接口
}

5 HashBag源码与Demo

  • 源码
public class HashBag<E> extends AbstractMapBag<E> implements Serializable {

    public HashBag() {
super(new HashMap<E, MutableInteger>());
} public HashBag(final Collection<? extends E> coll) {
this();
super.addAll(coll); // AbstractMapBag的addAll方法
}
} // 内部由一个Map实现
public abstract class AbstractMapBag<E> implements Bag<E> {
/** 用一个Map来放球,key为球,value为数量 */
private transient Map<E, MutableInteger> map;
/** 背包有多少球 */
private int size;
/** fail fast iterators的安全机制 */
private transient int modCount;
/** 有哪几种球的 */
private transient Set<E> uniqueSet; public boolean add(final E object) {
return add(object, 1);
} // 很简单:如果map包含object,则取出value,并加上nCopies;不包含就新建即可。
public boolean add(final E object, final int nCopies) {
modCount++;
if (nCopies > 0) {
final MutableInteger mut = map.get(object);
size += nCopies;
if (mut == null) {
map.put(object, new MutableInteger(nCopies));
return true;
}
mut.value += nCopies;
return false;
}
return false;
} // 遍历删除
public boolean addAll(final Collection<? extends E> coll) {
boolean changed = false;
final Iterator<? extends E> i = coll.iterator();
while (i.hasNext()) {
final boolean added = add(i.next());
changed = changed || added;
}
return changed;
} public boolean remove(final Object object, final int nCopies) {
final MutableInteger mut = map.get(object);
if (mut == null) return false; // 不包含该object则返回false
if (nCopies <= 0) return false;
modCount++;
if (nCopies < mut.value) { // 如果背包中的数量比删除的数量多则相减
mut.value -= nCopies;
size -= nCopies;
} else { // 如果背包中的数量比删除的数量少则直接删完
map.remove(object);
size -= mut.value;
}
return true;
} // 集合类的toString都需要用到StringBuilder进行append,这样可以提升性能
public String toString() {
if (size() == 0) {
return "[]";
}
final StringBuilder buf = new StringBuilder();
buf.append('[');
final Iterator<E> it = uniqueSet().iterator();
while (it.hasNext()) {
final Object current = it.next();
final int count = getCount(current);
buf.append(count);
buf.append(':');
buf.append(current);
if (it.hasNext()) {
buf.append(',');
}
}
buf.append(']');
return buf.toString();
} public int getCount(final Object object) {
final MutableInteger count = map.get(object);
return count == null ? 0 : count.value;
} }
  • demo
@Slf4j // lombok
public class Main {
public static void main(String[] args) {
HashBag<Integer> bag = new HashBag<>();
bag.add(1);
bag.add(2);
bag.add(3); System.out.println(bag); // [1:1,1:2,1:3] 第一个值为出现次数,第二个value值
boolean remove2 = bag.remove(2, 1); // 删除2值1次,发现有并删除返回true
boolean remove4 = bag.remove(4, 1); // 删除4值1次,发现没有返回false
// remove2:true remove4:false
log.info("remove2:{} remove4:{}",remove2,remove4);
System.out.println(bag); // [1:1,1:3]
}
}

6 HashCode重写

  • 设计Hash的容器类都需要重写equals方法和hashCode方法来实现自己希望的逻辑,如:HashBag、HashSet或者希望自定义对象作为HashMap的值
public class Main {
public static void main(String[] args) {
Student student1 = new Student("andy", 11,99.5);
Student student2 = new Student("andy", 11,99.5);
System.out.println(student1.equals(student2)); // true Set<Student> set = new HashSet<>();
set.add(student1);
set.add(student2);
System.out.println(set.size()); // 1
} @Getter
@Setter
static class Student {
private String name;
private int age;
private double score; public Student(String name, int age,double score) {
this.name = name;
this.age = age;
this.score = score;
} @Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj.getClass() != this.getClass()) return false;
Student student = (Student) obj;
return student.name.equals(this.name)
&& student.age == this.age
&& student.score == this.score;
} @Override
public int hashCode() {
int hash = 17;
hash = hash * 31 + name.hashCode();
hash = hash * 31 + age;
hash = hash * 31 + Double.valueOf(score).hashCode();
return hash;
}
}
}
  • 注意:lombok的@Data注解会自动帮你重写equals和hashCode方法,不需要时请不要使用@Data注解,避免造成不必要的麻烦

ListUtils的简单集合操作和原理的更多相关文章

  1. Python语法速查: 2. 列表、元组、字典、集合操作

    返回目录 (1)通用序列操作 “序列”表示索引为非负整数的有序对象集合,列表.元组.字符串都属于序列.区别在于:列表是可变的,而元组和字符串是不可变的.序列的通用操作他们都可以用. 操作或方法 简述 ...

  2. java集合对象实现原理

    1.集合包 集合包是java中最常用的包,它主要包括Collection和Map两类接口的实现. 对于Collection的实现类需要重点掌握以下几点: 1)Collection用什么数据结构实现? ...

  3. Stream常用操作以及原理探索

    Stream常用操作以及原理 Stream是什么? Stream是一个高级迭代器,它不是数据结构,不能存储数据.它可以用来实现内部迭代,内部迭代相比平常的外部迭代,它可以实现并行求值(高效,外部迭代要 ...

  4. salesforce 零基础开发入门学习(三)sObject简单介绍以及简单DML操作(SOQL)

    salesforce中对于数据库操作和JAVA等语言对于数据库操作是有一定区别的.salesforce中的数据库使用的是Force.com 平台的数据库,数据表一行数据可以理解成一个sObject变量 ...

  5. Python 集合set添加删除、交集、并集、集合操作符号

    在Python中集合set是基本数据类型的一种,它有可变集合(set)和不可变集合(frozenset)两种.创建集合set.集合set添加.集合删除.交集.并集.差集的操作都是非常实用的方法. 1. ...

  6. SequoiaDB 系列之二 :SequoiaDB的简单CRUD操作

    上一篇通过一系列的操作,终于把SequoiaDB的集群部署到单台机器上了. 建议去安装体验一下吧. 在整个环境的部署的体验来看,并没有MongoDB的部署简单,但是比MongoDB的部署要清晰.Mon ...

  7. sql的集合操作

    原文转自:http://blog.csdn.net/qsyzb/article/details/12560917 SELECT语句的查询结果是元组的集合,所以多个SELECT语句的结果可进行集合操作. ...

  8. 集合操作出现的ConcurrentModificationException(源码分析)

    摘要: 为了保证线程安全,在迭代器迭代的过程中,线程是不能对集合本身进行操作(修改,删除,增加)的,否则会抛出ConcurrentModificationException的异常. 示例: publi ...

  9. java中的集合操作类(未完待续)

    申明: 实习生的肤浅理解,如发现有错误之处.还望大牛们多多指点 废话 事实上我写java的后台操作,我每次都会遇到一条语句:List<XXXXX> list = new ArrayList ...

随机推荐

  1. linux提权方法(不断总结更新)

    目录 1.suid提权 2.rbash绕过 3.git提权 4.Linux Kernel 4.4.x (Ubuntu 16.04) - 'double-fdput()' bpf(BPF_PROG_LO ...

  2. .net core 修改 Identity/AspNetUsers 数据库

    众所周知,.net core有一套完整的用户管理功能.使用它就能实现用户的管理及登录登出功能.现在问题来了,我们有时候需要添加一些字段,该怎么办呢?当然是修改他呀.修改方法参考链接:https://m ...

  3. linux下添加动态链接库路径、动态库加载等方法

    linux下添加动态链接库路径的方法 2017年01月20日 10:08:17 阅读数:5596   Linux共享库路径配置 Linux下找不到共享库文件的典型现象为明明已经安装某个软包(如libn ...

  4. poj1734

    Sightseeing trip Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9078   Accepted: 3380 ...

  5. kotlin 泛型约束

    fun <T:Comparable<T>> sort(list :List<T>){} 冒号之后指定的类型就是泛型参数的上界,对于泛型参数T,只允许使用Compar ...

  6. 【思考】为什么说Bagging减少variance,Boosting减少bias?(转载)

    具体讨论可见于此知乎问题,有很多种理解方向,甚至这一个命题可能本来就不成立!

  7. 003-多线程-JUC集合-Set-CopyOnWriteArrayList

    一.概述 它是线程安全的无序的集合,可以将它理解成线程安全的HashSet.有意思的是,CopyOnWriteArraySet和HashSet虽然都继承于共同的父类AbstractSet:但是,Has ...

  8. 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_16.RabbitMQ研究-与springboot整合-生产者代码

    springBoot给我们提供了 RarbbitTemplate发送消息 创建测试类,因为我们是基于SpringBoot的来写的测试类.所以要加上@SpringBootTest和@RunWith的注解 ...

  9. PAT 甲级 1028 List Sorting (25 分)(排序,简单题)

    1028 List Sorting (25 分)   Excel can sort records according to any column. Now you are supposed to i ...

  10. JAVA 基础编程练习题36 【程序 36 移动位置】

    36 [程序 36 移动位置] 题目:有 n 个整数,使其前面各数顺序向后移 m 个位置,最后 m 个数变成最前面的 m 个数 package cskaoyan; public class cskao ...