java集合

Posted 爽走不解释

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java集合相关的知识,希望对你有一定的参考价值。

这一章补充上一章的内容、

一、迭代器与增强for循环

List strList = new ArrayList<>();
	//使用增强for循环
	for(String obj : strList)
		System.out.println(obj);
	
	
    //使用iterator
Iterator it = strList.iterator();
	while(it.hasNext())
		String obj = it.next();
		System.out.println(obj);
	

Iterator(迭代器):
在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK专门提供了一个接口java.util.Iterator。Iterator接口也是Java集合中的一员,但它与Collection、Map接口有所不同,Collection接口与Map接口主要用于存储元素,而Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器 。

想要遍历Collection集合,那么就要获取该集合迭代器完成迭代操作。获取迭代器的方法:

public Iterator iterator(): 获取集合对应的迭代器,用来遍历集合中的元素的

Iterator接口的常用方法如下:

boolean hasNext():判断集合里是否存在下一个元素。如果有,hasNext()方法返回 true。
Object next():返回集合里下一个元素。
void remove():删除集合里上一次next方法返回的元素。

代码示例;

public class IteratorStudy 
    public static void main(String[] args) 
        // 使用多态方式 创建对象
        Collection<String> col=new ArrayList<>();
        col.add("一号");
        col.add("二号");
        col.add("三号");
 
        //遍历
        //使用迭代器 遍历   每个集合对象都有自己的迭代器
        Iterator<String> it = col.iterator();
        //  泛型指的是 迭代出 元素的数据类型
 
        for(;it.hasNext();)        //判断是否有迭代元素
            String s = it.next();   //获取迭代出的元素
            System.out.println(s);
        
    

 运行结果
 一号
 二号
 三号

public class Test 
    public static void main(String[] args) 

        HashMap<String, String> map = new HashMap <>();
        map.put("001","java");
        map.put("002",".NET");
        map.put("003","C#");
        System.out.println(map.size());//显示集合中的数量

        for (Map.Entry<String, String> stringStringEntry : map.entrySet()) 
            System.out.println(stringStringEntry.getKey() + stringStringEntry.getValue());
        //循环输出集合中的值
        System.out.println(map.get("002")); //查询编号为002的图书
          //map.remove("003"); //删除编号为003的图书


注意:

  • Iterator只能单向移动。
  • Iterator.remove()是唯一安全的方式来在迭代过程中修改集合;如果在迭代过程中以任何其它的方式修改了基本集合将会产生未知的行为。而且每调用一次next()方法,remove()方法只能被调用一次,如果违反这个规则将抛出一个异常。

迭代器的原理:
在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。
图解:

增强for循环
增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。

语法格式:

for(元素的数据类型  变量 : Collection集合or数组) 
      //写操作代码

注意:增强for循环只用于遍历Collection和数组。通常只进行遍历元素,不要在遍历的过程中对集合元素进行增删操作。

代码示例:

   1、遍历数组
public class ForStudy 
    public static void main(String[] args) 
		int[] arr = 3,5,6,87;
       	//使用增强for遍历数组
		for(int a : arr)//a代表数组中的每个元素
			System.out.println(a);
		
	


2、遍历集合 
public class ForStudy2
    public static void main(String[] args)         
    	Collection<String> coll = new ArrayList<String>();
    	coll.add("张三");
    	coll.add("李四");
    	coll.add("老王");
 
    	//使用增强for遍历
    	for(String s :coll)        //接收变量s代表 代表被遍历到的集合元素
    		System.out.println(s);
    	
	

二、集合的子类用法异同点

1、ArrayList和LinkedList的区别

  • ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
  • 对于随机访问get和set,ArrayList绝对优于LinkedList,因为LinkedList要移动指针。
  • 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。

2.HashTable与HashMap的区别

相同点:

  • 都实现了Map、Cloneable、java.io.Serializable接口。
  • 都是存储"键值对(key-value)"的散列表,而且都是采用拉链法实现的。

不同点:

  • HashMap允许key和value为null,而HashTable不允许。
  • HashTable是同步的,而HashMap不是。所以HashMap适合单线程环境,HashTable适合多线程环境。
  • 在Java1.4中引入了LinkedHashMap,HashMap的一个子类,假如你想要遍历顺序,你很容易从HashMap转向LinkedHashMap,但是HashTable不是这样的,它的顺序是不可预知的。
  • HashMap提供对key的Set进行遍历,因此它是fail-fast的,但HashTable提供对key的Enumeration进行遍历,它不支持fail-fast。
  • HashTable被认为是个遗留的类,如果你寻求在迭代的时候修改Map,你应该使用CocurrentHashMap。
  • HashMap只支持Iterator(迭代器)遍历。而Hashtable支持Iterator(迭代器)和Enumeration(枚举器)两种方式遍历。

3、ArrayList和Vector的区别
相同点:

  • 两者都是基于索引的,内部由一个数组支持。
  • 两者维护插入的顺序,我们可以根据插入顺序来获取元素。
  • ArrayList和Vector的迭代器实现都是fail-fast的。
  • ArrayList和Vector两者允许null值,也可以使用索引值对元素进行随机访问。

不同点:

  • Vector是同步的,而ArrayList不是。然而,如果你寻求在迭代的时候对列表进行改变,你应该使用CopyOnWriteArrayList。
  • ArrayList比Vector快,它因为有同步,不会过载。
  • ArrayList更加通用,因为我们可以使用Collections工具类轻易地获取同步列表和只读列表。

4、Array和ArrayList的区别

  • Array可以容纳基本类型和对象,而ArrayList只能容纳对象。
  • Array是指定大小的,而ArrayList大小是固定的。
  • Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。尽管ArrayList明显是更好的选择,但也有些时候Array比较好用。

什么适合用Array呢?
(1)如果列表的大小已经指定,大部分情况下是存储和遍历它们。
(2)对于遍历基本数据类型,尽管Collections使用自动装箱来减轻编码任务,在指定大小的基本类型的列表上工作也会变得很慢。
(3)如果你要使用多维数组,使用[][]比List>更容易。

5、线程安全与安全
线程安全(Thread-safe)的集合对象:
Vector
HashTable
StringBuffer

非线程安全的集合对象:
ArrayList :
LinkedList:
HashMap:
HashSet:
TreeMap:
TreeSet:
StringBulider:

6、Collection 和 Collections的区别

  • java.util.Collection
    是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
  • java.util.Collections
    是一个包装类(工具类/帮助类)。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,用于对集合中元素进行排序、搜索以及线程安全等各种操作,服务于Java的Collection框架。

代码示例:

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

public class TestCollections  

    public static void main(String args[])  
        //注意List是实现Collection接口的 
        List list = new ArrayList(); 
        double array[] =  112, 111, 23, 456, 231 ; 
        for (int i = 0; i < array.length; i++)  
            list.add(new Double(array[i])); 
         
        Collections.sort(list); 
        for (int i = 0; i < array.length; i++)  
            System.out.println(list.get(i)); 
         
        // 结果:23.0 111.0 112.0 231.0 456.0 
     

6、HashSet、LinkedHashSet、TreeSet的区别

HashSet

  • 不能保证元素的排列顺序,顺序有可能发生变化。
  • 不是同步的。
  • 集合元素可以是null,但只能放入一个null

当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值也相等。

注意:
如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。

LinkedHashSet

  • LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
  • LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。

TreeSet

  • TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
  • TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0。

7、自然排序与定制排序
自然排序
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。

  • Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object
    obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是负数,则表明obj1小于obj2。如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0。

定制排序
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法。

代码示例;

package com.test;  

import java.util.HashSet;  
import java.util.LinkedHashSet;  
import java.util.TreeSet;  

/**  
 * @description 几个set的比较  
 *    HashSet:哈希表是通过使用称为散列法的机制来存储信息的,元素并没有以某种特定顺序来存放;  
 *    LinkedHashSet:以元素插入的顺序来维护集合的链接表,允许以插入的顺序在集合中迭代;  
 *    TreeSet:提供一个使用树结构存储Set接口的实现,对象以升序顺序存储,访问和遍历的时间很快。  
 * @author Zhou-Jingxian  
 *  
 */  
public class SetDemo   

    public static void main(String[] args)   

        HashSet<String> hs = new HashSet<String>();  
        hs.add("B");  
        hs.add("A");  
        hs.add("D");  
        hs.add("E");  
        hs.add("C");  
        hs.add("F");  
        System.out.println("HashSet 顺序:\\n"+hs);  

        LinkedHashSet<String> lhs = new LinkedHashSet<String>();  
        lhs.add("B");  
        lhs.add("A");  
        lhs.add("D");  
        lhs.add("E");  
        lhs.add("C");  
        lhs.add("F");  
        System.out.println("LinkedHashSet 顺序:\\n"+lhs);  

        TreeSet<String> ts = new TreeSet<String>();  
        ts.add("B");  
        ts.add("A");  
        ts.add("D");  
        ts.add("E");  
        ts.add("C");  
        ts.add("F");  
        System.out.println("TreeSet 顺序:\\n"+ts);  
      

输出结果:

HashSet 顺序:[D, E, F, A, B, C]
LinkedHashSet 顺序:[B, A, D, E, C, F]
TreeSet 顺序:[A, B, C, D, E, F]

8、HashMap、Hashtable、LinkedHashMap和TreeMap比较

  • HashMap 是一个最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。遍历时,取得数据的顺序是完全随机的。HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用Collections的synchronizedMap方法使HashMap具有同步的能力
  • Hashtable 与HashMap类似,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢。
  • LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的,也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
  • 如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。LinkedHashMap实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。对于LinkedHashMap而言,它继承与HashMap、底层使用哈希表与双向链表来保存所有元素。其基本操作与父类HashMap相似,它通过重写父类相关的方法,来实现自己的链接列表特性。
  • TreeMap实现SortMap接口,内部实现是红黑树。能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator
    遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key的值为null。非同步的。
  • 一般情况下,我们用的最多的是HashMap,HashMap里面存入的键值对在取出的时候是随机的,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map
    中插入、删除和定位元素,HashMap 是最好的选择。

欢迎评论留言

以上是关于java集合的主要内容,如果未能解决你的问题,请参考以下文章

Java 集合多条件多规则排序 升序 降序 空值处理

集合-Java中Arrays.sort()自定义数组的升序和降序排序

java8新特性:对map集合排序,根据key或者value操作排序(升序降序)

你还在用迭代器处理集合吗?试试Stream,真香!

java集合

Java笔记:集合框架