在许多应用场合,一组数据的长度不是固定的,比如一个单位的员工数目是变化的,有老员工跳槽,也有新员工进来。

为了使程序能够方便的存储和操纵数目不固定的一组数据,JDK类库提供了Java集合,位于java.util包中。与Java数组不同,Java集合中不能存放基本类型数据,而只能存放对象的引用。

Java集合主要包含4种类型:

  • Set(集):集合中的对象不按特定方式排序,并且没有重复的对象。它的有些实现类能对集合中的对象按特定方式排序 。
  • List(列表):集合中的对象按照索引位置排序,可以有重复的对象,允许按照对象在集合中的索引位置检索对象。这与数组有些相似。
  • Queue(队列):集合中的对象按照先进先出的规则来排列。在队列的末尾添加元素,在队列的头部删除元素,可以有重复对象。双向队列则允许在队列的头部和尾部添加和删除元素。
  • Map(映射):集合中的每个元素包含一对键(Key)对象和值(vlaue)对象,集合中没有重复的键对象,值对象可以重复。它的有些实现类能对集合中的键对象进行排序。

上面说的Set集合与数学中的集合最接近,两者都不允许有重复的元素。Set、List和Queue都是Collection接口的子接口,Map接口没有继承Collection接口。

主要集合类的类框图

Collection和Iterator接口

在Collection接口中声明了如下的方法:

Set接口、List接口和Queue接口都继承了Collection接口,因此可以对Set对象、List对象和Queue对象调用以上方法。

Collection接口的Iterator()方法返回一个Iterator对象,不同的集合返回各自实现的Iterator接口实例。Iterator接口中声明了如下方法:

  • hasNext():判断集合中的元素是否遍历完毕,如果没有返回true。
  • next():返回下一个元素。
  • remove():从集合中删除由next()方法返回的当前元素。

当通过Collection集合的iterator()方法得到一个Iterator对象后,如果当前线程或其他线程接着又通过Collection集合的某些方法对集合进行了修改操作(排除当前Iterator对象的remove()方法),接下来调用这个Iterator对象的next()方法会导致java.util.ConcurrentModificatonException运行时异常。

Iterator对象运用了快速失败机制(fail-fast),一旦监测到集合已被修改,就会抛出ConcurrentModificationException运行时异常,而不是显示修改后的当前内容,这可以避免潜在的由于共享资源竞争而导致的并发问题。

Set集合

其实Set是最简单的一种集合,内部的元素不按照特定的方式排序,并且没有重复对象。Set接口主要由两个实现类:HashSet类和TreeSet类。

  • HashSet

HashSet按照哈希算法来存取集合中的对象,存取速度比较快。HashSet还有一个子类LinkedHashSet类,它不仅实现了哈希算法,还实现了链表数据结构。链表数据结构能提高插入和删除元素的性能。

当向集合中加入一个对象时,HashSet会调用对象的hashCode()方法获得哈希码,然后根据这个哈希码进一步计算出对象在集合中的存放位置。

那hashCode()方法如何计算哈希的呢?在Object类中定义了hashCode()和equals()方法,equals()方法按照内存地址比较两个对象是否相等,同样的hashCode()方法也是按照内存地址进行计算哈希值的。

为了保证能正常工作,要求当两个对象用equals()方法比较结果为true时,它们的哈希码也相等。否则会导致HashSet无法正常工作,因为两个对象的哈希码不一样,HashSet计算出不同的位置,两个对象会存在不同位置,不会发生equals判断。

反过来,两个对象的equals方法比较不相等,却并不要求两个对象的哈希码也不相等。不过尽量保证用有不同的哈希码,可以减少哈希冲突,提高hashSet的性能。

  • TreeSet

TreeSet实现了SortedSet接口,具有排序功能。下面代码演示了这一功能:

Set set=new TreeSet<>();

set.add(8);

set.add(7);

set.add(6);

set.add(9);

for(int i:set)

System.out.print(i+" ");

运行结果

那么TreeSet是如何对对象进行排序的呢?TreeSet支持两种排序方式:自然排序和客户化排序,默认情况下TreeSet采用自然排序方式。

  • 自然排序

使用自然排序时,向TreeSet集合中加入的对象的类必须实现了Comparable接口。在JDK中有一部分类实现了Comparable接口,如Integer、Double和String等。

Comparable接口有一个compareTo(Object o)的方法,返回整型。对于表达式x.compareTo(y),如果返回值为0,表示x和y相等;如果返回值大于0,表示x大于y;如果返回值小于0,表示x小于y。

  • 客户化排序

使用客户化排序时,向TreeSet集合中加入的对象的类必须实现了java.util.Comparator接口或Comparable接口,两个接口的作用是相同的,只是前者必须指定被比较对象类型。

如果加入的对象的类没有实现Comparable/Comparator接口,会抛出异常“该类 cannot be cast to java.lang.Comparable”:

public class Demo {

public static void main(String[] args) {

Set set=new TreeSet<>();

set.add(new A(8));

set.add(new A(7));

set.add(new A(6));

set.add(new A(9));

for(A a:set)

System.out.print(a.num+" ");

}

}

class A{

public int num;

public A(int num){

this.num=num;

}

}

值得注意的是对于已经存在于TreeSet中的对象,修改其中会引起compareTo()方法返回值改变的属性后,TreeSet不会对集合进行排序。例如如下代码:

class A implements Comparable{

public int num;

public A(int num){

this.num=num;

}

@Override

public int compareTo(Object o) {

A b=(A)o;

if(this.num>b.num){

return 1;

}else if(this.num

return -1;

}else{

return 0;

}

}

}

public static void main(String[] args) {

Set set=new TreeSet<>();

A a1=new A(8);

set.add(a1);

set.add(new A(7));

set.add(new A(6));

set.add(new A(9));

System.out.print("排序后的结果:");

for(A a:set)

System.out.print(a.num+" ");

a1.num=100;

System.out.print("修改一个元素的属性后的结果:");

for(A a:set)

System.out.print(a.num+" "); //不会改变已经排好的顺序

set.add(new A(99));

System.out.print("再新增元素后的结果:");

for(A a:set)

System.out.print(a.num+" ");

}

可见TreeSet修改了元素的某个属性后,TreeSet不会重新排序。最适合TreeSet排序的是不可变类(即创建对象后,它们属性不能被修改)。

List(列表)

List的特征是其元素按照线性方式存储(即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的),集合中允许存放重复对象。主要的实现类:

ArrayList:

代表长度可变的数组。允许对元素进行快速的随机访问,但是向其中插入和删除元素的速度较慢。实现了RandomAccess接口,RandomAccess接口仅仅是标识该类具有良好的快速随机访问的性能。

LinkedList:

在实现中采用链表数据结构。对顺序访问做了优化,向List中插入和删除元素的速度较快,随机访问则相对较慢。LinkedList独有addFirst()、addLast()、getFirst()、getLast()、removeFirst()和removeLast()方法,这些方式可以将其作为堆栈、队列和双向队列使用。

  • 访问列表的元素

客户程序可以按照对象在集合中的索引位置来检索对象,如下代码:

List list=new ArrayList<>();

list.add(3);

list.add(4);

list.add(3);

list.add(2);

for(int i=0;i

System.out.print(list.get(i)+" ");

运行结果

List的iterator()方法和Set的一样,也能返回Iterator对象,例如:

Iterator it=list.iterator();

while(it.hasNext()){

System.out.print(it.next()+" ");

}

同样也可以用foreach,例如:

for(Integer i:list){

System.out.print(i+" ");

}

  • 为列表排序

List只能对加入其中的对象按照索引位置(即元素在List中的位置)进行排序,如果希望对List中的对象按照客户指定的方式排序,可以借助Comparator接口和Collections类。Collections类是Java集合类库中的辅助类,它提供的sort()静态方法用于对List中的对象进行排序:

  1. sort(List list):对list中的对象进行自然排序
  2. sort(List list,Comparator comparator):对List中的对象进行客户化排序,comparator参数指定排序方式。

List list=new ArrayList<>();

list.add(3);

list.add(4);

list.add(3);

list.add(2);

Collections.sort(list);

for(Integer i:list)

System.out.print(i+" ");

排序后结果

  • ListIterator接口

List的listIterator()方法返回一个ListIterator对象,ListIterator接口继承了Iterator接口,此外还提供了专门操纵列表的方法:

  1. add():向列表中插入一个元素
  2. hasNext():判断列表中是否还有下一个元素
  3. hasPrevious():判断列表中是否还有上一个元素
  4. next():返回列表中的下一个元素
  5. previous():返回列表的上一个元素
  • 获得固定长度的List对象

java.util.Arrays类的asList()方法能够把一个Java数组包装为一个List对象,这个List对象代表固定长度的数组。所有对List对象的操作都会被作用到包装前的Java数组。看Arrays类的源码可以知道返回的List对象其实是Arrays类自定义的一个List集合实现类

Arrays的asList方法

由于数组的长度不能改变,因此调用该List对象的add()和remove()方法,会抛出java.lang.UnsupportedOperationException运行时异常:

  • 比较Java数组和各种List实现类的性能

除了ArrayList、LinkedList外,在JDK1.0时候有个Vector类,在JDK2.0时候也把其改为实现了List接口。可以写一个程序分别对数组、ArrayList、LinkedList和Vector进行随机访问、遍历操作和增删操作,比较这几种集合的性能,可以得出类似下图的表格:

可以看出,对Java数组进行随机访问和遍历操作具有最快速度;对LinkedList进行插入和删除操作具有最快的速度;对ArrayList进行随机访问也具有较快的速度。Vector类在各方面都没有突出的性能,属于历史集合类,已经不建议使用。

Queue(队列)

火车站售票大厅排队等待购票的现象就是队列的表现,后加入的人排在队列的末尾,排在队列头部的人优先购票后离开队列。Java中,java.util.Queue接口表示队列,特点是向末尾添加元素,从队列头部删除元素,队列中允许有重复元素。

  • 向Queue加入元素的方法
  1. boolean add(E e) ,向队列末尾添加元素,如果队列已满,会抛出IllegalStateException
  2. boolean offer(E e) ,向队列末尾添加元素,如果队列已满,会返回false
  • 从Queue中删除元素的方法
  1. E remove(),删除头部的元素,如果队列为空,抛出NoSuchElementException
  2. E poll(),删除头部的元素,如果队列为空,返回null
  • 从Queue中获取元素
  1. E element(),返回队列头部的元素,不删除它。如果队列为空,抛出NoSuchElementException
  2. E peek(),返回队列头部的元素,不删除它。如果队列为空,返回null

Deque(双向队列)

Deque接口是Queue接口的子接口,特点是在队列的头部或尾部都可以添加或删除元素。LinkedList类就实现了Deque接口。

  • 向Deque头部或尾部添加元素
  1. void addFirst(E e)
  2. void addLast(E e)
  3. void offerFirst(E e)
  4. void offerLast(E e)

如果队列已满,前两个方法抛出IllegalStateException,而后两个方法返回false。

  • 从Deque头部或尾部删除元素
  1. E removeFirst()
  2. E removeLast()
  3. E pollFirst()
  4. E pollLast()

如果队列为空,前两个方法抛出NoSuchElementException,后两个方法返回null。

  • 从Deque头部或尾部获取元素

E getFirst()

E getLast()

E peekFirst()

E peekLast()

如果队列为空,前两个方法抛出NoSuchElementException,后两个方法返回null。

PriorityQueue(优先级队列)

它会按照排序的方式对对了中元素进行排序和检索。因此加入到PriorityQueue中的对象必须实现Comparable接口。

值的注意的是,优先级队列使用Iterator遍历时,输出结果没有进行排序,而调用针对队列首尾的方法会进行排序。

Map(映射)

Map是一种把键对象和值对象进行映射的集合,它的每一个元素都包含一对键对象和值对象,而且值对象仍可以是Map类型,依此类推,可以形成多级映射。

向Map集合中加入元素时,必须提供一对键对象和值对象,从Map集合中检索对象时,只要给出键对象,就会返回对应的值对象。

加入和检索对象

Map集合中的键对象不允许重复,也就是说,任意两个键对象通过equals()方法比较的结果都是false。对于值对象则没有唯一性的要求。因此,可以将任意多个键对象映射到同一个值对象上:

Map map=new HashMap<>();

map.put("1

java list 两个集合比较 不存在则新增 存在修改_Java之集合相关推荐

  1. java 8 两个list_java集合框架综述

    一.集合框架图 简化图: 说明:对于以上的框架图有如下几点说明 1.所有集合类都位于java.util包下.Java的集合类主要由两个接口派生而出:Collection和Map,Collection和 ...

  2. java中两种遍历集合的方式_Java中Map集合的两种遍历方式

    Java中的map遍历有多种方法,从最早的Iterator,到java5支持的foreach,再到java8 Lambda,让我们一起来看下Java中Map集合的两种遍历方式! 关于遍历Map集合的几 ...

  3. Java求两集合中元素交集的四种方法对比总结

    hello,你好呀,我是灰小猿,一个超会写bug的程序猿! 最近在做项目的时候有用到对两个集合中的元素进行对比求其交集的情况,因为涉及到的数据量比较大,所以在进行求两个集合中元素交集的时候,就应该考虑 ...

  4. Java判断两个集合是否具有交集以及如何获得交集

    Java判断两个集合是否具有交集以及如何获得交集 一.Java判断两个集合是否具有交集 1.Collections.disjoint 2.CollectionUtils.containsAny 3.C ...

  5. java集合总结_Java中集合总结

    Java数组的长度是固定的,为了使程序能够方便地存储和操作数目不固定的一组数据,JDK类库提供了Java集合,这些集合类都位于java.util包中,但是与数组不同的是,集合中不能存放基本类型数据,而 ...

  6. java 泛型集合应用_Java泛型集合的应用和方法

    展开全部 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以62616964757a686964616fe78988e69d8331333 ...

  7. java 有序容器_Java 容器集合框架概览

    Java Collections Framework 集合的概念 集合collection,有时叫做容器container,把多个元素组成一个单元. 早期的Java (pre-1.2) 中包含了Vec ...

  8. [转] 有关java中两个整数的交换问题

    转载申明:本文主要是用于自己学习使用,为了完善自己的只是框架,没有任何的商业目的. 原文来源:有关Java中两个整数的交换问题 如果侵权,麻烦告之,立刻删除. 在程序开发的过程,要交换两个变量的内容, ...

  9. 关于java集合的知识点_java中集合的知识点

    1.JAVA中集合都存放在java.util包中 2.JAVA集合中主要分为三种类型:Set,List,Map.我写的这篇文章主要是对Set和List的理解 3.Collection是最基本的集合接口 ...

最新文章

  1. 用lambda对std::list排序 - 力为的技术博客 - C++博客
  2. GBDT指标重要性计算
  3. MinGW 和 MSVC 下,使用 FILE 类型的一个奇怪的问题
  4. 判断子序列不同的子序列两个字符串的删除操作编辑距离
  5. QML基础类型之palette
  6. 就业模拟试题_Java(答案)
  7. [Debugging]分析博客园提交评论的校验规则
  8. % mysql 代表_MySQL中的星号(*)和百分号(%)代表表示什么,MySQL的库名、表名、字段名、字段值是否区分大...
  9. java基础-public/private/protected的具体区别
  10. 利用dns来ping通所有主机名的方法,免去一条条配置hosts
  11. wifi的country code
  12. 这5小段代码轻松实现数据可视化(Python+Matplotlib)
  13. 何凯明新作ViTDET:目标检测领域,颠覆分层backbone理念
  14. matlab求t分布的p值,在R中如何求给定分布和统计量的p-value
  15. 痘痘告诉你,身体哪里生病了
  16. 《美食街》项目---(登录篇){ ‘blur‘焦点属性,resetFields(),meta对象,$confirm,window.location.href=‘/‘}
  17. 2.2 法力池的创建和视觉特效———自制卡牌游戏之旅
  18. Leetcode之跳跃游戏整理
  19. 士兵队列训练问题 (队列 c++)
  20. DirectX游戏开发之3D角色动起(下)

热门文章

  1. JS实现每隔几个字符添加字符(串):实现每间隔10个字就换行一次,多用于echarts横坐标的显示文本拥挤换行;实现间隔8个字符就添加❤❤
  2. 修改ceph crush map,并指定到资源池
  3. Scrapy和MongoDB的应用
  4. Jtabbedpane设置透明、Jpanel设置透明
  5. 【BZOJ1015】【JSOI2008】星球大战 并查集
  6. mysql like 命中索引
  7. 367. Valid Perfect Square
  8. C#让windows程序只运行一次
  9. emacs按键绑定详解
  10. 四层和七层负载均衡的区别