Java集合

Java集合:Collection(List,Set,Queue);Map;Iterator(依附于Collection对象,主要用于遍历Collection集合中的元素)

Set:HashSet,LinkedHashSet,TreeSet,EnumSet(都是线程不安全的)

  • HashSet:除了排序外都比TreeSet要好,默认大小是16
  • LinkedHashSet:HashSet的子类,使用链表维护元素的插入顺序(如果没有重写compareTo方法),遍历比HashSet快,其他比HashSet慢(链表开销)
  • TreeSet:调用compareTo方法使元素按升序排列(红黑树算法),compareTo返回0则认为相等
  • EnumSet:性能最好,但只能保存同一个枚举类的枚举值作为集合元素

List:ArrayList,LinkedList,Vector

  • ArrayList:数组形式实现,随机访问(get)性能好
  • LinkedList:链表形式实现,迭代器遍历,插入删除性能好,此外还提供了双端队列和栈的功能
  • Vector:以数组形式实现,线程安全但很少用

    ArrayList和Vector的区别(它们都是基于数组实现):

    • ArrayList在内存不够时默认是old*1.5 + 1个,Vector是默认扩展1倍,默认大小都为10
    • Vector属于线程安全级别的,但是大多数情况下不使用Vector,因为线程安全需要更大的系统开销,它和hashtable一样,属于很古老的集合

Map:HashMap,LinkedHashMap,HashTable,TreeMap,EnumMap

  • HashMap:性能比HashTable好,线程不安全,(判断key是否一样通过equals()和hashCode),推荐使用,底层由数组和链表实现,当一个map填满了75%(负载因子)的bucket时候,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中;JDK1.8中如果链表长度大于8会把链表转化为红黑树。
  • HashTable:线程安全,不允许加入null,(判断key是否一样通过equals()和hashCode)
  • LinkedHashMap:HashMap的子类,使用双向链表维护元素的插入顺序,性能略低于HashMap,迭代遍历快
  • TreeMap:调用compareTo方法使key按升序排列,compareTo返回0则认为key相等
  • EnumMap:性能最好,但只能保存同一个枚举类的枚举值作为key
  • ConcurrentHashMap:线程安全,原子操作,比hashtable效率高,对数据分块加锁
    当多线程对ConcurrentHashMap 操作时,不是完全锁住map, 而是锁住相应的segment 。这样提高了并发效率。缺点:当遍历ConcurrentMap中的元素时,需要获取所有的segment 的锁,使用遍历时慢。锁的增多,占用了系统的资源。使得对整个集合进行操作的一些方法(例如 size() 或 isEmpty() )的实现更加困难,因为这些方法要求一次获得许多的锁,并且还存在返回不正确的结果的风险。

    HashMap和Hashtable的区别(它们都是基于数组和链表实现):

    • Hashtable的方法是同步的(加了synchronized),HashMap则是非同步的,所以在多线程场合要手动同步HashMap(Collections的synchronizedMap()或者ConcurrentHashMap),这个区别就像Vector和ArrayList一样。
    • Hashtable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以)。
    • Hashtable使用Enumeration和Iterator遍历,HashMap使用Iterator遍历。
    • Hashtable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,增加方式是翻倍。

注:我们事先已知集合的使用场景,知道集合的大概范围,我们最好是指定初始化容量,这样对资源的利用会更加好,尤其是大数据量的前提下,效率的提升和资源的利用会显得更加具有优势。

foreach,iterator ,for循环

要使用foreach语法,必须是数组,或者该类必须实现Iterable接口才可以,语法如下:

for(T t : Iterable) { .... }  

如果查看编译后的字节码,会发现foreach最终被编译器转为对iterator.next()的调用,这些jdk给隐藏起来了。迭代器这些方法的具体实现,各个集合类实现都不一样,有自己的方法。如ArrayList是数组的存储,循环的是数组的方法,而LinkedList是链表,循环的是链表的方法。

关于foreach和iterator的效率问题,其实他们的实现的过程是一样的。 如下面代码:

List list = new ArrayList();   
for (Object obj : list) {   
    System.out.println(obj);   
}  

相当于

List list = new ArrayList();   
Object obj;   
for (Iterator iterator = list.iterator(); iterator.hasNext();) {   
    obj = iterator.next();   
    System.out.println(obj);   
}  

for循环与for-each循环效率:
这个要从具体实现的迭代器来看,如ArrayList由于是数组的存储方式,直接使用for循环的get效率会更快,LinkedList是链式存储机制,所以使用foreach的迭代会高效很多。 写代码使用foreach语法是首选,代码更优美,也不容易出错。

另外关于foreach删除list的元素出错可参考 for each删除List中的元素出错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值