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. python 度分秒转度

    #必须是u类型==================u==================== by gisoracle def dmstod(dms): #arcpy.AddMessage(" ...

  2. SSH交互式脚本StrictHostKeyChecking选项 benchmode=yes

    SSH 公钥检查是一个重要的安全机制,可以防范中间人劫持等黑客攻击.但是在特定情况下,严格的 SSH 公钥检查会破坏一些依赖 SSH 协议的自动化任务,就需要一种手段能够绕过 SSH 的公钥检查. 什 ...

  3. spring常用模式--委派模式

    1.委派模式简介 在常用的23种设计模式中其实面没有委派模式(delegate)的影子,但是在Spring中委派模式确实用的比较多的一种模式. 在spring中的体现:Spring MVC框架中的Di ...

  4. MobileNet V2深入理解

    转载:https://zhuanlan.zhihu.com/p/33075914 MobileNet V2 论文初读 转载:https://blog.csdn.net/wfei101/article/ ...

  5. 用Keras搭建神经网络 简单模版(四)—— RNN Classifier 循环神经网络(手写数字图片识别)

    # -*- coding: utf-8 -*- import numpy as np np.random.seed(1337) from keras.datasets import mnist fro ...

  6. react 组件创建

    /** * 数据屏蔽 * Created by 2016-12-02. */ import React, {Component} from 'react'; export default class ...

  7. prometheus部署安装

    1. 下载&部署 # 下载 [root@prometheus src]# cd /usr/local/src/ [root@prometheus src]# wget https://gith ...

  8. WPScan使用完整攻略:如何对WordPress站点进行安全测试

    转载自FreeBuf.COM 严正声明:本文仅限于技术探讨,严禁用于其他目的. 写在前面的话 在这篇文章中,我将告诉大家如何使用WPScan来对WordPress站点进行安全测试. WPScan是Ka ...

  9. 什么是UEFI

    UEFI是什么?也许我们大多数用户对这个概念很模糊.uefi可以做什么,有什么具体的应用?虽然不知道具体是做什么的,但是我们经常会在BIOS设置中发现UEFI的踪迹.因为现在越来越多的电脑已经使用了U ...

  10. 最新 盛趣游戏java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.盛趣游戏等10家互联网公司的校招Offer,因为某些自身原因最终选择了盛趣游戏.6.7月主要是做系统复习.项目复盘.Leet ...