ListUtils的简单集合操作和原理
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的简单集合操作和原理的更多相关文章
- Python语法速查: 2. 列表、元组、字典、集合操作
返回目录 (1)通用序列操作 “序列”表示索引为非负整数的有序对象集合,列表.元组.字符串都属于序列.区别在于:列表是可变的,而元组和字符串是不可变的.序列的通用操作他们都可以用. 操作或方法 简述 ...
- java集合对象实现原理
1.集合包 集合包是java中最常用的包,它主要包括Collection和Map两类接口的实现. 对于Collection的实现类需要重点掌握以下几点: 1)Collection用什么数据结构实现? ...
- Stream常用操作以及原理探索
Stream常用操作以及原理 Stream是什么? Stream是一个高级迭代器,它不是数据结构,不能存储数据.它可以用来实现内部迭代,内部迭代相比平常的外部迭代,它可以实现并行求值(高效,外部迭代要 ...
- salesforce 零基础开发入门学习(三)sObject简单介绍以及简单DML操作(SOQL)
salesforce中对于数据库操作和JAVA等语言对于数据库操作是有一定区别的.salesforce中的数据库使用的是Force.com 平台的数据库,数据表一行数据可以理解成一个sObject变量 ...
- Python 集合set添加删除、交集、并集、集合操作符号
在Python中集合set是基本数据类型的一种,它有可变集合(set)和不可变集合(frozenset)两种.创建集合set.集合set添加.集合删除.交集.并集.差集的操作都是非常实用的方法. 1. ...
- SequoiaDB 系列之二 :SequoiaDB的简单CRUD操作
上一篇通过一系列的操作,终于把SequoiaDB的集群部署到单台机器上了. 建议去安装体验一下吧. 在整个环境的部署的体验来看,并没有MongoDB的部署简单,但是比MongoDB的部署要清晰.Mon ...
- sql的集合操作
原文转自:http://blog.csdn.net/qsyzb/article/details/12560917 SELECT语句的查询结果是元组的集合,所以多个SELECT语句的结果可进行集合操作. ...
- 集合操作出现的ConcurrentModificationException(源码分析)
摘要: 为了保证线程安全,在迭代器迭代的过程中,线程是不能对集合本身进行操作(修改,删除,增加)的,否则会抛出ConcurrentModificationException的异常. 示例: publi ...
- java中的集合操作类(未完待续)
申明: 实习生的肤浅理解,如发现有错误之处.还望大牛们多多指点 废话 事实上我写java的后台操作,我每次都会遇到一条语句:List<XXXXX> list = new ArrayList ...
随机推荐
- 能不能支持在线查看word,excel这样的文件?还有拖拽上传功能?
https://forum.enhancer.io/topic/5adea0cdce69735af635fcd8 方法1. 用一个自定义窗口, 自定义窗口里放一个iframe 假设你的 word 的地 ...
- RAFT选举算法-分布式数据库困惑
在做HIS研发工作的时候一直想完善其数据组件,想做一个分布式的数据库支持系统.但一直以来都不清楚这个选举算法应怎么做,原来有一个叫raft的算法https://www.cnblogs.com/just ...
- chrome jssip
WebRTC 实现了基于网页的视频会议,标准是WHATWG 协议,目的是通过浏览器提供简单的javascript就可以达到实时通讯(Real-Time Communications (RTC))能力 ...
- Ubuntu: Linux下查看本机显示器分辨率(xrandr)
版权声明:转载请注明出处 https://blog.csdn.net/JNingWei/article/details/75044598 Linux下查看本机显示器分辨率: $ xrandr Sc ...
- Flutter移动电商实战 --(23)分类页_左侧类别导航制作
自动生成dart类 https://javiercbk.github.io/json_to_dart/ 生成的代码 class Autogenerated { String code; String ...
- 【Java/JDBC】借助ResultSetMetaData,从数据库表中抽取字段信息存成Excel文件
本例工程下载:https://files.cnblogs.com/files/xiandedanteng/FindNotnullColumns20191102-3.rar 工作中曾有个为42张表建立测 ...
- PHP学习之工厂模式
<?php //工厂模式 interface Doing { function eat(); function sleep(); } class Cat implements Doing { f ...
- JMeter-jp@gc - PerfMon Metrics Collector-CPU监控工具的配置及使用(win版本)
服务器端放这个 如果端口号被占用,默认报这个错: 如果默认的4444端口被占用的修改: C:\Users\Administrator>CD E:\E:\apache-jmeter-4.0\Ser ...
- mac 设置 MySQL 数据库默认编码(字符集)为 UTF-8
mac 设置 MySQL 数据库默认编码(字符集)为 UTF-8 原文链接:https://juejin.im/post/5bbdca76e51d45021147de44 鉴于有些刚接触 MySQ ...
- Antecedent Membership Functions相关资料
属于模糊控制领域 前件隶属函数(Antecedent Membership Functions) 基于模糊近似的强化学习方法研究 - 豆丁网 https://www.docin.com/p-13022 ...