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. 能不能支持在线查看word,excel这样的文件?还有拖拽上传功能?

    https://forum.enhancer.io/topic/5adea0cdce69735af635fcd8 方法1. 用一个自定义窗口, 自定义窗口里放一个iframe 假设你的 word 的地 ...

  2. RAFT选举算法-分布式数据库困惑

    在做HIS研发工作的时候一直想完善其数据组件,想做一个分布式的数据库支持系统.但一直以来都不清楚这个选举算法应怎么做,原来有一个叫raft的算法https://www.cnblogs.com/just ...

  3. chrome jssip

    WebRTC 实现了基于网页的视频会议,标准是WHATWG 协议,目的是通过浏览器提供简单的javascript就可以达到实时通讯(Real-Time Communications (RTC))能力 ...

  4. Ubuntu: Linux下查看本机显示器分辨率(xrandr)

    版权声明:转载请注明出处 https://blog.csdn.net/JNingWei/article/details/75044598   Linux下查看本机显示器分辨率: $ xrandr Sc ...

  5. Flutter移动电商实战 --(23)分类页_左侧类别导航制作

    自动生成dart类 https://javiercbk.github.io/json_to_dart/ 生成的代码 class Autogenerated { String code; String ...

  6. 【Java/JDBC】借助ResultSetMetaData,从数据库表中抽取字段信息存成Excel文件

    本例工程下载:https://files.cnblogs.com/files/xiandedanteng/FindNotnullColumns20191102-3.rar 工作中曾有个为42张表建立测 ...

  7. PHP学习之工厂模式

    <?php //工厂模式 interface Doing { function eat(); function sleep(); } class Cat implements Doing { f ...

  8. JMeter-jp@gc - PerfMon Metrics Collector-CPU监控工具的配置及使用(win版本)

    服务器端放这个 如果端口号被占用,默认报这个错: 如果默认的4444端口被占用的修改: C:\Users\Administrator>CD E:\E:\apache-jmeter-4.0\Ser ...

  9. mac 设置 MySQL 数据库默认编码(字符集)为 UTF-8

    mac 设置 MySQL 数据库默认编码(字符集)为 UTF-8   原文链接:https://juejin.im/post/5bbdca76e51d45021147de44 鉴于有些刚接触 MySQ ...

  10. Antecedent Membership Functions相关资料

    属于模糊控制领域 前件隶属函数(Antecedent Membership Functions) 基于模糊近似的强化学习方法研究 - 豆丁网 https://www.docin.com/p-13022 ...