[Java]集合的小抄 Java初学者必备

文章目录

        • 【背景】
          • Collections
        • List
          • ArrayList
            • 优势操作
            • 劣势操作
          • LinkedList
            • 优势
            • 劣势
            • 最基本的两种检索集合中的所有对象的方法:
          • CopyOnWriteArrayList
          • 补充说明
          • Stack
        • Map
          • Map 的常用方法:
          • HashMap
          • LinkedHashMap
          • TreeMap
          • ConcurrentHashMap
            • ConcurrentSkipListMap
          • 补充说明
            • 关于null
        • Set
          • Set接口主要实现了两个实现类:
          • 补充说明
        • Queue
            • 注意
          • LinkedList
          • ArrayDeque
          • PriorityQueue
          • ConcurrentLinkedQueue/ConcurrentLinkedDeque
          • PriorityBlockingQueue
          • DelayQueue
          • ArrayBlockingQueue
          • LinkedBlockingQueue/LinkedBlockingDeque
          • SynchronousQueue
          • 补充说明

【背景】

在尽可能短的篇幅里,将所有集合与并发集合的特征,实现方式,性能捋一遍。适合所有”精通Java”其实还不那么自信的人阅读。

Collection

Collections

Set 和List 都继承了Conllection,Map没有
Collection接口的方法

  • boolean add(Object o) :向集合中加入一个对象的引用
  • void clear() :删除集合中所有的对象,即不再持有这些对象的引用
  • boolean isEmpty() :判断集合是否为空
  • boolean contains(Object o): 判断集合中是否持有特定对象的引用
  • Iterartor iterator() : 返回一个Iterator对象,可以用来遍历集合中的元素
  • boolean remove(Object o):从集合中删除一个对象的引用
  • int size() :返回集合中元素的数目
  • Object[] toArray() :返回一个数组,该数组中包括集合中的所有元素
  • 关于:Iterator() 和toArray() 方法都用于集合的所有的元素,前者返回一个Iterator对象,后者返回一个包含集合中所有元素的数组。
    Iterator接口声明了如下方法:
  • hasNext(): 判断集合中元素是否遍历完毕,如果没有,就返回true
  • next() :返回下一个元素
  • remove():从集合中删除上一个有next()方法返回的元素。
    Set 的 add()方法是如何判断对象是否已经存放在集合中?
    boolean isExists=false;Iterator iterator=set.iterator();while(it.hasNext())           {String oldStr=it.next();if(newStr.equals(oldStr)){isExists=true;}

List

  • List的特征是其元素以线性方式存储,集合中可以存放重复对象。
ArrayList
  • 以数组实现。节约空间,但数组有容量限制。
  • 超出限制时会增加50%容量,默认第一次插入元素时创建大小为10的数组。
优势操作
  • get(i)/set(i,e) 访问
  • add(e) 末尾插入
劣势操作

System.arraycopy()来移动部分受影响的元素,性能变差

  • add–add(i,e) 按下标插入
  • add(i,e), remove(i), remove(e) 删除元素
LinkedList
  • 以双向链表实现,链表无容量限制
  • 双向链表本身使用了更多空间,需要额外的链表指针操作
优势

在链表两头的操作能省掉指针的移动

  • add()
  • addFirst()
  • removeLast()
  • iterator()上的remove()
劣势
  • 按下标访问元素–get(i)/set(i,e) 要遍历链表将指针移动到位(如果i>数组大小的一半,会从末尾移起)
  • 插入、删除元素时修改前后节点的指针即可,仍要遍历部分链表的指针才能移动到下标所指的位置
最基本的两种检索集合中的所有对象的方法:
1: 用for循环和get()方法:for(int i=0; i<list.size();i++){System.out.println(list.get(i));}2: 使用 迭代器(Iterator):Iterator it=list.iterator();while(it.hashNext){System.out.println(it.next);}
CopyOnWriteArrayList
  • 支持读多写少的并发情况
    -增加了addIfAbsent(e)方法,会遍历数组来检查元素是否已存在,性能可想像的不太好
  • 如果更新频率较高,或数组较大时使用Collections.synchronizedList(list),对所有操作用同一把锁来保证线程安全更好
补充说明
  • 按值返回下标–contains(e), indexOf(e), remove(e) 都需遍历所有元素进行比较,性能可想像的不太好
  • 没有按元素值排序的SortedList,在线程安全类中也没有无锁算法的ConcurrentLinkedList,凑合着用Set与Queue中的等价类时,会缺少一些List特有的方法
Stack
  • Stack 的常用方法:
push( num) 入栈
pop() 栈顶元素出栈
empty() 判定栈是否为空
peek() 获取栈顶元素
search(num) 判端元素num是否在栈中,如果在返回1,不在返回-1。    注意pop()和peek()的区别。pop()会弹出栈顶元素并返回栈顶的值,peek()只是获取栈顶的值,但是并不会把元素从栈顶弹出来  

Map

  • Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象,键对象不允许重复。
  • Map没有继承于Collection接口
  • 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
Map 的常用方法:
 1 添加,删除操作:Object put(Object key, Object value): 向集合中加入元素Object remove(Object key):   删除与KEY相关的元素void putAll(Map t):   将来自特定映像的所有元素添加给该映像void clear(): 从映像中删除所有映射2 查询操作:Object get(Object key): 获得与关键字key相关的值
HashMap
  • 以Entry[]数组实现的哈希桶数组,用Key的哈希值取模桶数组的大小可得到数组下标
  • 插入元素时,如果两条Key落在同一个桶(如哈希值1和17取模16后都属于第一个哈希桶)。Entry用一个next属性实现多个Entry以单向链表存放,后入桶的Entry将next指向桶当前的Entry
  • 查找key时(如哈希值为17的),先定位到第一个哈希桶,然后以链表遍历桶里所有元素,逐个比较其key值
  • 当Entry数量达到桶数量的**75%**时(很多文章说使用的桶数量达到了75%,但看代码不是),会成倍扩容桶数组,并重新分配所有原来的Entry
LinkedHashMap
  • 扩展HashMap增加双向链表的实现(最占内存的数据结构)
  • 支持iterator()时按Entry的插入顺序来排序(但是更新不算, 如果设置accessOrder属性为true,则所有读写访问都算)
    实现上是在Entry上再增加属性before/after指针,插入时把自己加到Header Entry的前面去。
    如果所有读写访问都要排序,还要把前后Entry的before/after拼接起来以在链表中删除掉自己
TreeMap
  • 以红黑树实现,篇幅所限详见入门教程
  • 支持iterator()时按Key值排序,可按实现了Comparable接口的Key的升序排序,或由传入的Comparator控制。
  • 可想象的,在树上插入/删除元素的代价一定比HashMap的大
    -支持SortedMap接口,如firstKey(),lastKey()取得最大最小的key,或sub(fromKey, toKey), tailMap(fromKey)剪取Map的某一段
ConcurrentHashMap
  • 并发优化的HashMap,默认16把写锁(可以设置更多),有效分散了阻塞的概率,而且没有读锁(因为put/remove动作是个原子动作(比如put是一个对数组元素/Entry 指针的赋值操作),读操作不会看到一个更新动作的中间状态)
  • 数据结构为Segment[],Segment里面才是哈希桶数组,每个Segment一把锁。Key先算出它在哪个Segment里,再算出它在哪个哈希桶里
  • 支持ConcurrentMap接口,如putIfAbsent(key,value)与相反的replace(key,value)与以及实现CAS的replace(key, oldValue, newValue)
ConcurrentSkipListMap
  • JDK6新增的并发优化的SortedMap,以SkipList实现
  • SkipList是红黑树的一种简化替代方案,是个流行的有序集合算法,篇幅所限见入门教程
  • Concurrent包选用它是因为它支持基于CAS的无锁算法,而红黑树则没有好的无锁算法
  • 它的size()不能随便调,会遍历来统计,效率低
补充说明
关于null
  • HashMap和LinkedHashMap是随意的,
  • TreeMap没有设置Comparator时key不能为null;
  • ConcurrentHashMap在JDK7里value不能为null,JDK8里key与value都不能为null;
  • ConcurrentSkipListMap是所有JDK里key与value都不能为null

Set

  • Set对每个对象只接受一次,并使用自己内部的排序方法
  • Set几乎都是内部用一个Map来实现, 因为Map里的KeySet就是一个Set,而value是假值,全部使用同一个Object。
  • Set的特征也继承了那些内部Map实现的特征。
Set接口主要实现了两个实现类:
  • HashSet : HashSet类按照哈希算法来存取集合中的对象,存取速度比较快,内部是HashMap
  • TreeSet : TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序。
  • LinkedHashSet:内部是LinkedHashMap。
  • ConcurrentSkipListSet:内部是ConcurrentSkipListMap的并发优化的SortedSet。
  • CopyOnWriteArraySet:内部是CopyOnWriteArrayList的并发优化的Set,利用其addIfAbsent()方法实现元素去重,如前所述该方法的性能很一般。
补充说明
  • 好像少了个ConcurrentHashSet,本来也该有一个内部用ConcurrentHashMap的简单实现,但JDK偏偏没提供。Jetty就自己封了一个,Guava则直接用java.util.Collections.newSetFromMap(new ConcurrentHashMap()) 实现

Jetty 是一个开源的servlet容器,它为基于Java的web容器
Guava是一种基于开源的Java库,谷歌很多项目使用它的很多核心库

Queue


Queue是在两端出入的List,所以也可以用数组或链表来实现。

  • add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
  • remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
  • element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
  • offer 添加一个元素并返回true 如果队列已满,则返回false
  • poll 移除并返问队列头部的元素 如果队列为空,则返回null
  • peek 返回队列头部的元素 如果队列为空,则返回null
  • put 添加一个元素 如果队列满,则阻塞
  • take 移除并返回队列头部的元素 如果队列为空,则阻塞
注意
  • remove、element、offer 、poll、peek 其实是属于Queue接口。

  • add remove element操作在队满或者队空的时候会报异常。

  • offer poll peek 在队满或者队空的时候不会报异常。

  • put take操作属于阻塞操作。队满队空均会阻塞。
    –普通队列–

LinkedList
  • 以双向链表实现的LinkedList既是List,也是Queue。
  • 它是唯一一个允许放入null的Queue。
ArrayDeque
  1. 以循环数组实现的双向Queue。大小是2的倍数,默认是16。

  2. 普通数组只能快速在末尾添加元素,为了支持FIFO,从数组头快速取出元素,就需要使用循环数组n有队头队尾两个下标:

  • 弹出元素时,队头下标递增;
  • 加入元素时,如果已到数组空间的末尾,则将元素循环赋值到数组0,同时队尾下标指向0,再插入下一个元素则赋值到数组[1],队尾下标指向1。
  • 如果队尾的下标追上队头,说明数组所有空间已用完,进行双倍的数组扩容。
PriorityQueue
  • PriorityQueue 类实质上维护了一个有序列表。加入到 Queue 中的元素根据它们的天然排序(通过其 java.util.Comparable 实现)或者根据传递给构造函数的 java.util.Comparator 实现来定位。
  • 用二叉堆实现的优先级队列,详见入门教程
  • 不再是FIFO而是按元素实现的Comparable接口或传入Comparator的比较结果来出队,数值越小,优先级越高,越先出队
  • 注意其iterator()的返回不会排序。

–线程安全的队列–

ConcurrentLinkedQueue/ConcurrentLinkedDeque
  • ConcurrentLinkedQueue 是基于链接节点的、线程安全的队列。并发访问不需要同步。因为它在队列的尾部添加元素并从头部删除它们,所以只要不需要知道队列的大 小,

  • ConcurrentLinkedQueue 对公共集合的共享访问就可以工作得很好。收集关于队列大小的信息会很慢,需要遍历队列。

  • 无界的并发优化的Queue,基于链表,实现了依赖于CAS的无锁算法。

  • ConcurrentLinkedQueue的结构是单向链表和head/tail两个指针,因为入队时需要修改队尾元素的next指针,以及修改tail指向新入队的元素两个CAS动作无法原子,所以需要的特殊的算法,篇幅所限见入门教程。

–线程安全的阻塞队列–

  • BlockingQueue的队列长度受限,用以保证生产者与消费者的速度不会相差太远,避免内存耗尽
  • 队列长度设定后不可改变
  • 当入队时队列已满,或出队时队列已空,不同函数的效果见下表:
PriorityBlockingQueue
  • 一个由优先级堆支持的无界优先级队列。(无容量限制)
  • 无界的并发优化的PriorityQueue,也是基于二叉堆。
  • 使用一把公共的读写锁。虽然实现了BlockingQueue接口,其实没有任何阻塞队列的特征,空间不够时会自动扩容。
DelayQueue
  • 一个由优先级堆支持的、基于时间的调度队列。
  • 内部包含一个PriorityQueue,同样是无界的。
  • 元素需实现Delayed接口,每次调用时需返回当前离触发时间还有多久,小于0表示该触发了。
  • pull()时会用peek()查看队头的元素,检查是否到达触发时间。ScheduledThreadPoolExecutor用了类似的结构。
  • 一个存放Delayed 元素的无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且poll将返回null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于或等于零的值时,则出现期满,poll就以移除这个元素了。此队列不允许使用 null 元素。
ArrayBlockingQueue
  • 一个由数组支持的有界队列(指定容量)
  • 定长的并发优化的BlockingQueue,基于循环数组实现。
  • 有一把公共的读写锁与notFull、notEmpty两个Condition管理队列满或空时的阻塞状态。
  • 可以选择是否需要公平性,如果公平参数被设置true,等待时间最长的线程会优先得到处理(其实就是通过将ReentrantLock设置为true来 达到这种公平性的:即等待时间最长的线程会先操作)。通常,公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队 列,此队列按 FIFO(先进先出)原则对元素进行排序。
LinkedBlockingQueue/LinkedBlockingDeque
  • 一个由链接节点支持的可选有界队列。
  • 可选定长的并发优化的BlockingQueue,基于链表实现,所以可以把长度设为Integer.MAX_VALUE。
  • 利用链表的特征,分离了takeLock与putLock两把锁,继续用notEmpty、notFull管理队列满或空时的阻塞状态。
SynchronousQueue
  • 一个利用 BlockingQueue 接口的简单聚集(rendezvous)机制
补充说明

JDK7有个LinkedTransferQueue,transfer(e)方法保证Producer放入的元素,被Consumer取走了再返回,比SynchronousQueue更好,有空要学习下。

来源:http://www.topthink.com/topic/11679.html
参考文章:https://blog.csdn.net/imbingoer/article/details/85886312
参考文章:https://blog.csdn.net/imbingoer/article/details/85884474

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/426137.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

excel生成mysql语句_通过SQL语句直接实现Excel与数据库的导入导出

1、在SQL数据库中直接从Excel里面查询数据&#xff1a;select \* fromOPENROWSET(MICROSOFT.JET.OLEDB.4.0,Excel 5.0;HDRYES;DATABASEc:\\test.xls,sheet1$)2、从Excel文件中,导入数据到SQL数据库中,select \* into 表 from![](http://images.csdn.net/syntaxhighlighting/Out…

基础知识小记:

什么时候用这些循环&#xff1f; 1,、for(i;i<n;i) 知道循环的起止数, 循环中需要用到不断递增/递减的变量 2、for(String s:slist) 叫foreach循环, 遍历数组/集合中元素用的 为了减少代码量 3、while 不知道确切的循环次数, 但知道循环结束条件时使用 4、do while 先执行一…

java学习(127):finally语句

finally作为异常处理的一部分&#xff0c;它只能用在try/catch语句中&#xff0c;并且附带一个语句块&#xff0c;表示这段语句最终一定会被执行&#xff08;不管有没有抛出异常&#xff09;&#xff0c;经常被用在需要释放资源的情况下。 之前在写爬虫的时候数据库连接的频率…

[剑指offer]面试题第[6]题[JAVA][旋转数组的最小数字][二分法]

####【问题描述】 把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转&#xff0c;输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转&#xff0c;该数组的最小值为1。 NOTE&#xff1a;给出…

mysql合并多条纪录字段_Mysql应用mysql合并多条记录的单个字段去一条记录编辑

《MysqL应用MysqL合并多条记录的单个字段去一条记录编辑》要点&#xff1a;本文介绍了MysqL应用MysqL合并多条记录的单个字段去一条记录编辑&#xff0c;希望对您有用。如果有疑问&#xff0c;可以联系我们。测试用表结构&#xff1a;代码如下:---- 表的结构 tet--CREATE TABLE…

git之项目上传

git之项目上传 需求&#xff1a;将项目代码上传至github 前期准备&#xff1a; 1.github账号注册 2.安装git环境&#xff0c;可以打开且使用git shell. 3.生成SSH key并与github账号绑定 步骤&#xff1a; 1.进入gitshell 2. 进入到项目指定的目录下&#xff0c;适用git命令初始…

[leedcode][409][java]

####【题目描述】 给定一个包含大写字母和小写字母的字符串&#xff0c;找到通过这些字母构造成的最长的回文串。在构造过程中&#xff0c;请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。注意: 假设字符串的长度不会超过 1010。示例 1:输入: "abccccdd…

玩转oracle 11g(35):rman备份-参数文件spfile损坏恢复

1.参数文件spfile损坏恢复 (1)选择“开始”“运行”&#xff0c;输入cmd&#xff0c;按回车。 (2)输入“ set oracle_siddocare”&#xff0c;按回车。 &#xff08;oracle_sid根据实际名称填写&#xff09; (3)输入“rman target /”&#xff0c;按回车 如果在64bit下安装…

python获取页面隐藏元素_selenium操作隐藏的元素(python+Java)

有时候我们会碰到一些元素不可见&#xff0c;这个时候selenium就无法对这些元素进行操作了。例如&#xff0c;下面的情况&#xff1a;Python页面主要通过“display:none”来控制整个下拉框不可见。这个时候如果直接操作这个下拉框&#xff0c;就会提示&#xff1a;from seleniu…

docker 配置文件:/etc/docker/daemon.json

/etc/docker/daemon.json 是 docker 的配置文件&#xff0c;默认是没有的&#xff0c;需要我们手动创建&#xff0c;可配置项如下&#xff1a; [rootlocalhost ~]$ vim /etc/docker/daemon.json {"authorization-plugins": [],"data-root": "", …

[leedcode][JAVA][365][BFS]

【问题描述】 有两个容量分别为 x升 和 y升 的水壶以及无限多的水。请判断能否通过使用这两个水壶&#xff0c;从而可以得到恰好 z升 的水&#xff1f;如果可以&#xff0c;最后请用以上水壶中的一或两个来盛放取得的 z升 水。你允许&#xff1a;装满任意一个水壶 清空任意一个…

玩转oracle 11g(36):rman备份-控制文件丢失恢复

ORA-00205: error in identifying control file, check alert log for more info 检查oracle的报警日志包含类似报错&#xff1a; ORA-00210: cannot open the specified control file ORA-00202: control file: D:\ORACLE\PRODUCT\10.2.0\ORADATA\DOCARE\C ONTROL01.CTL OR…

=在 java中怎么表示_在Java中各种类型运算符的介绍与其基本使用方式(有具体使用示例)...

一.算数运算符基本四则运算符 - * / %(使用规则简单&#xff0c;正常使用即可)注意事项&#xff1a;a) int/int 结果还是 int 要保留小数需要使用double来计算int a 1;int b 2;System.out.println(a/b);//结果为0b)0不能作为出除数c)%表示取余不仅仅可以对int求模&#xff0…

【旧文章搬运】无Device的驱动如何通信

原文发表于百度空间&#xff0c;2009-07-14 标准的驱动与ring3的通信过程是这样的&#xff1a;驱动中创建设备&#xff0c;并为设备创建符号链接&#xff0c;ring3用CreateFile打开符号链接得到设备句柄&#xff0c;然后DeviceIoControl发送ControlCodeDeviceIoControl的内容被…

[Leedcode][JAVA]第[945]题

【问题描述】 给定整数数组 A&#xff0c;每次 move 操作将会选择任意 A[i]&#xff0c;并将其递增 1。返回使 A 中的每个值都是唯一的最少操作次数。示例 1:输入&#xff1a;[1,2,2] 输出&#xff1a;1 解释&#xff1a;经过一次 move 操作&#xff0c;数组将变为 [1, 2, 3]。…

玩转oracle 11g(37):rman备份-数据库指定文件恢复

.数据库指定数据文件恢复 启动数据库的时候报错 ORA-01157: cannot identify/lock data file 5 - see DBWR trace file ORA-01110: data file 5: D:\ORACLE\PRODUCT\10.2.0\ORADATA\DOCARE\AP MEDCOMM.DBF ORA-27041: unable to open file OSD-04002: 无法打开文件 O/S-Erro…

java xpath 解析xml_使用XPATH解析XML文件

使用XPATH解析XML文件import java.util.Iterator;import java.util.List;import org.dom4j.Document;import org.dom4j.DocumentException;import org.dom4j.Node;import org.dom4j.io.SAXReader;public class TestXPath {public static void main(String[] args) throws Docum…

并发编程-concurrent指南-原子操作类-AtomicBoolean

类AtomicBoolean 可以用原子方式更新的 boolean 值。有关原子变量属性的描述&#xff0c;请参阅 java.util.concurrent.atomic 包规范。AtomicBoolean 可用在应用程序中&#xff08;如以原子方式更新的标志&#xff09;&#xff0c;但不能用于替换 Boolean。 2.构造函数 1.Atom…

[剑指offer]面试题第[7]题[JAVA][斐波那契数列][递归]

【问题描述】 大家都知道斐波那契数列&#xff0c;现在要求输入一个整数n&#xff0c;请你输出斐波那契数列的第n项&#xff08;从0开始&#xff0c;第0项为0&#xff09;。 n<39 【解答思路】 1.递归&#xff08;面试避免&#xff09; O(n^2) public class Solution {pu…