热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

集合相关的常用工具类

1.简介Java中的集合类既可以当做放其他数据的容器,又可以当做常见的数据结构使用。Java中提供了很多好用的工具类来操作这些集合类。本篇博客就来介绍下常用的集合工具类。集合常用的

1. 简介

Java中的集合类既可以当做放其他数据的容器,又可以当做常见的数据结构使用。Java中提供了很多好用的工具类来操作这些集合类。本篇博客就来介绍下常用的集合工具类。集合常用的工具类大体可以分为3类:



  • JDK本身提供的工具类;

  • Guava提供的工具类;

  • Apache common-Collection提供的工具类


2. JDK提供的工具类

主要由下面三个:



  • Arrays

  • Collections

  • Objects

Arrays是操作数组对象的工具类,Collections是操作集合对象的工具类。Objects是操作引用数据类型对象的工具类。

Arrays的常用方法:

普通排序

Arrays.sort(int[] a)
Arrays.sort(int[] a, int fromIndex, int toIndex)

其他非boolean基础数据类型的数组对象以及实现Comparable接口的类的数组对象均有此方法。

并行排序:JDK1.8新增。

Arrays.parallelSort(int[] a)
Arrays.parallelSort(int[] a, int fromIndex, int toIndex)

其他非boolean基础数据类型的数组对象以及实现Comparable接口的类的数组对象均有此方法。

并行计算:JDK1.8新增,支持函数式编程,根据传入的方法进行一次计算。

Arrays.parallelPrefix(int[] array, IntBinaryOperator op)
Arrays.parallelPrefix(int[] array, int fromIndex, int toIndex, IntBinaryOperator op)

其他非boolean基础数据类型的数组对象以及实现Comparable接口的类的数组对象均有此方法。

二分法查找:前提是该数组已经进行了排序

Arrays.binarySearch(int[] a, int key)
Arrays.binarySearch(int[] a, int fromIndex, int toIndex, int key)

其他非boolean基础数据类型的数组对象以及实现Comparable接口的类的数组对象均有此方法。

判断两个数组是否相等

Arrays.equals(int[] a, int[] a2)

其他基础数据类型的数组对象以及Object数组对象均有此方法,Object调用的是equels()方法。

对数组进行填充

Arrays.fill(int[] a, int val)
Arrays.fill(int[] a, int fromIndex, int toIndex, int val)

其他基础数据类型的数组对象以及Object数组对象均有此方法。

复制数组

Arrays.copyOf(int[] original, int newLength),返回赋值后的数组,数组长度为newLength。
Arrays.copyOfRange(int[] original, int from, int to)

其他基础数据类型的数组对象以及Object数组对象均有此方法。Object数组为浅复制,即复制的是引用。

toString: 将元素用","隔开,包裹在"[ ]"内。

Arrays.toString(int[] a)

其他基础数据类型的数组对象以及Object数组对象均有此方法。Object数组为引用地址。

Arrays.deepToString(Object[] a)方法内部调用了a.toString()。

更改元素值:JDK1.8新增,支持函数式编程

setAll(int[] array, IntUnaryOperator generator)
setAll(long[] array, IntToLongFunction generator)
setAll(double[] array, IntToDoubleFunction generator)
setAll(T[] array, IntFunction generator)

该类方法支持这四种类型。每种类型均有对应的并行设置方法parallelSetAll()

数组转集合

Arrays.asList(T... a) 返回List

如果是Object数组对象,该方法生成的集合对象持有的是数组对象对应元素的引用。

生成并行遍历的Spliterator,JDK1.8新增

Arrays.spliterator(int[] array)
Arrays.spliterator(int[] array, int startInclusive, int endExclusive)

int、long、double和实现了Spliterator接口的类具有该类型方法。

生成Stream类,JDK1.8新增

Arrays.stream(int[] a)
Arrays.stream(int[] array, int startInclusive, int endExclusive)

int、long、double和实现了Stream接口的类具有该类型方法。

JDK1.8新增的方法基本都是与函数式变成或多核并行操作相关

接下来看看Arrays常用方法的源码。

1,Arrays.asList()的源码实现分析:

public static List asList(T... a) {
return new ArrayList<>(a); // 为什么JDK的设计者不直接使用ava.util.ArrayList呢?
}

这个ArrayList是数组的内部实现类,不是经常是用的java.util.ArrayList。这个内部类ArrayList是一个固定大小的list,不支持list.add()和list.remove(),这里一定要注意。

2,Arrays.sort()的源码实现分析:

public static void sort(int[] a) {
DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}

这里用到了DualPivotQuicksort.sort()。DualPivotQuicksort是java.util包下的final类,专门用来对基础数据类型的数据进行排序的。DualPivotQuicksort.sort()源码分析:

static void sort(int[] a, int left, int right, int[] work, int workBase, int workLen) {
// 对于数组长度小的情况采用快速排序
if (right - left sort(a, left, right, true);
return;
}
// 归并+快排 (引入了TimSort的run的概念)
...省略算法源码
}

快排算法sort()的源码分析:

private static void sort(int[] a, int left, int right, boolean leftmost) {
int length = right - left + 1;
// 对于数组长度很小的情况采用插入排序
if (length // 插入排序 insertion sort
...省略算法源码
}
// 双轴快排 dual-pivot quicksort
...省略算法源码(递归插入排序)
}

具体的算法实现源码不做深究,以后有机会的话写一些关于算法拾遗。这里主要是一些阀值要注意。

3,Arrays.sort(Object[] a)的源码实现分析:

public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested) // 如果用户强制要求使用传统的排序方法。
// -Djava.util.Arrays.useLegacyMergeSort=true
// 或者System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
legacyMergeSort(a); // 使用传统方法排序
else
ComparableTimSort.sort(a, 0, a.length, null, 0, 0); // 使用TimSort算法排序
}

传统的排序算法legacyMergeSort()源码:

private static void legacyMergeSort(Object[] a, int fromIndex, int toIndex) {
Object[] aux = copyOfRange(a, fromIndex, toIndex);
mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
}
private static void mergeSort(Object[] src, Object[] dest, int low, int high, int off) {
int length = high - low;
// 如果数组长度很小,采用插入排序 Insertion sort
if (length for (int i=low; i for (int j=i; j>low &&
((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
swap(dest, j, j-1);
return;
}
// 将数组分为两个子数组,分别使用递归排序Recursively sort,再进行合并排序
...省略算法源码
}

JDK1.8开始支持TimSort算法,源于Python中的TimSort(结合了merge sort 和 insertion sort)。

ComparableTimSort.sort()源码:

static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
assert a != null && lo >= 0 && lo <= hi && hi <= a.length;
int nRemaining = hi - lo;
if (nRemaining <2)
return; // 数组长度为0或1时无需排序
// 如果数组长度小,采用无合并形式的"mini-TimSort"排序
if (nRemaining int initRunLen = countRunAndMakeAscending(a, lo, hi);
binarySort(a, lo, hi, lo + initRunLen); // 二分插入排序
return;
}
// 1,遍历一遍数组,找到已经自然排序好顺序的序列;3,这个序列入栈(临时数组,排序后的数组就放在这里);
// 2,如果这个序列的长度 // 4,同样的方法寻找下一个分段并入另外一个栈;
// 5,合并排序两个栈中的序列;
// 6,重复4和5;
...省略算法源码
}

4,Arrays.parallelSort()的源码实现分析:

public static void parallelSort(byte[] a) {
int n = a.length, p, g;
if (n <= MIN_ARRAY_SORT_GRAN ||
(p = ForkJoinPool.getCommonPoolParallelism()) == 1)
DualPivotQuicksort.sort(a, 0, n - 1)
else
new ArraysParallelSortHelpers.FJByte.Sorter
(null, a, new byte[n], 0, n, 0,
((g = n / (p <<2)) <= MIN_ARRAY_SORT_GRAN) ?
MIN_ARRAY_SORT_GRAN : g).invoke();
}

Arrays.parallelSort()采用的是cilk排序算法。

cilk排序算法基本思想:



  1. 将数组分为两部分;

  2. 针对每一部分:a,再分为2部分(相当于1/4);b,针对每1/4部分进行排序;c,排序并合并这两个1/4;

  3. 将分别排序好的这两部分进行排序合并。

如果当前数组的长度a.length
  ForkJoinPool.getCommonPoolParallelism()获取当前ForkJoin线程池的并行度,跟机器的处理器核数有关,可以通过-Djava.util.concurrent.ForkJoinPool.common.parallelism=8或者System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","8")来指定,如果=1则表示不支持并行执行。

parallelSort()的基本实现思想:



  1. 将需要被排序的数组分为parallelism个子数组交由ForkJoin框架的每个并行线程执行;

  2. 每个并行线程将分配到的子数组又分为4个子数组按照cilk算法进行排序,没个1/4子数组都会按照DualPivotQuicksort.sort()排序;

  3. 最后将parallelism个子数组进行排序合并。

==================================华丽的分割线==================================

Collections的常用方法:

排序

Collections.sort(List list) T或其父类需要实现Comparable接口 Collections.sort(List list, Comparator c) Collections.sort()的源码:

public static void sort(List list, Comparator c) {
list.sort(c);
}

List.sort()的源码:

default void sort(Comparator c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c); // 调用Arrays.sort()来进行排序
ListIterator i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}

Collections.sort()最终调用的是Arrays.sort()进行排序。

查到索引

Collections.binarySearch(List> list, T key) Collections.binarySearch(List list, T key, Comparator c)

顺序反转

Collections.reverse(List list)

乱序

Collections.shuffle(List list)

指定元素互换

Collections.swap(List list, int i, int j)

填充

Collections.fill(List list, T obj)

复制

Collections.copy(List dest, List src)

求极值

Collections.min(Collection coll)

Collections.min(Collection coll, Comparator comp)

Collections.max(Collection coll)

Collections.max(Collection coll, Comparator comp)

转动元素

Collections.rotate(List list, int distance)

distance可以接受负数 将list元素整体向后移动distance的距离,原来最后的distance个元素放到最前面(有点类似与一个圆圈转动)

替换元素

Collections.replaceAll(List list, T oldVal, T newVal)

子集合索引

Collections.indexOfSubList(List source, List target)

Collections.lastIndexOfSubList(List source, List target)

如果不是子集合,返回-1

转换为不可变集合

Collections.unmodifiableCollection(Collection c)

将集合转换为不可变集合read-only。装饰者模式,使用final修饰iterator,增删元素的方法throw new UnsupportedOperationException()

Collections.unmodifiableSet(Set s)

Collections.unmodifiableList(List list)

Collections.unmodifiableMap(Map m)

转换为同步集合

Collections.synchronizedCollection(Collection c)

Collections.synchronizedCollection(Collection c, Object mutex) 指定mutex对象作为同步锁,将集合转换为线程安全的同步集合。装饰着模式,方法内使用了 synchronized (mutex) { ... }保证线程安全

Collections.synchronizedSet(Set s)

Collections.Collections.synchronizedSet(Set s, Object mutex)

Collections.synchronizedList(List list)

Collections.synchronizedList(List list, Object mutex)

Collections.synchronizedMap(Map)

元素受限制集合

Collections.checkedCollection(Collection c, Class type)

由于JDK1.5引入了泛型,采用该方法,保证运行期集合中增加的元素只能是指定的类型。同样是装饰着模式。

Collections.checkedQueue(Queue queue, Class type)

Collections.checkedSet(Set, Class)

Collections.checkedList(List, Class)

Collections.checkedMap(Map, Class, Class)

生成空的不可变集合

Collections.emptyIterator()

Collections.emptyListIterator()

Collections.emptyEnumeration()

Collections.emptySet()

Collections.emptyList()

Collections.emptyMap()

只有1个元素的不可变集合

Collections.singleton(T)

Collections.singletonList(T)

Collections.singletonMap(K, V)

拥有n个相同元素的不可变集合

Collections.nCopies(int, T)

反序比较器

Collections.reverseOrder(Comparator) 返回一个Comparator,返回值与参数值是相反顺序的比较器

转换为枚举类型的API

Collections.enumeration(Collection) 返回Enumeration

将Enumeration转换为集合

Collections.list(Enumeration) 返回ArrayList

元素在集合中的个数

Collections.frequency(Collection, Object) 返回int

两个元素是否有交集

Collections.disjoint(Collection, Collection) 返回boolean

增加元素

addAll(Collection c, T... elements)

由于List接口拥有listItegertor()方法,与List相关的大部分操作内部会判断阀值,超过阀值则采用listIterator遍历,小于阀值则采用for循环索引遍历。不同的方法阀值不同。

==================================华丽的分割线==================================

Objects类最主要就一个方法 Objects.equals(Object a, Object b)

public static boolean equals(Object a, Object b) {
return a == b || (a != null && a.equals(b));
}

其余的一些比如Obejcts.isNull(Object obj)、Objects.nonNull(Ojbect obj)主要是用来在Stream流式API操作的时候使用。


3. Guava工具类

任何对JDK集合框架有经验的程序员都熟悉和喜欢java.util.Collections包含的工具方法。Guava沿着这些路线提供了更多的工具方法:适用于所有集合的静态方法。这是Guava最流行和成熟的部分之一。

我们用相对直观的方式把工具类与特定集合接口的对应关系归纳如下:



































































集合接口属于JDK还是**Guava**对应的Guava工具类
CollectionJDKCollections2:不要和java.util.Collections混淆
ListJDKLists
SetJDKSets
SortedSetJDKSets
MapJDKMaps
SortedMapJDKMaps
QueueJDKQueues
MultisetGuavaMultisets
MultimapGuavaMultimaps
BiMapGuavaMaps
TableGuavaTables

在找类似转化、过滤的方法?请看第四章,函数式风格。

详细的介绍可以参考这个文章


4. Apache提供的Collection

Apache提供的集合工具类功能也非常强大。另外还提供了集合的求交集、并集和差集等功能。

具体可以参考官网


5. 参考



  • https://ifeve.com/google-guava-collectionutilities/


推荐阅读
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 在project.properties添加#Projecttarget.targetandroid-19android.library.reference.1..Sliding ... [详细]
author-avatar
手机用户2602908963
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有