集合

来源:互联网 发布:淘宝店铺发货无需物流 编辑:程序博客网 时间:2024/05/22 02:41

java集合大致可分为Set,List,Queue和Map其中Set代表无序,不可重复的集合,List代表有序,可重复的集合,Map代表具有映射关系的集合Queue代表一种队列集合的实现。

一.集合概述

数组元素既可以基本数据类型的值也可以是对象,集合只能保存对象。java集合主要由两个接口派生而出,Collection和Map。

二.Collection和Itertator,Collection接口是List,Set,和Queue接口的父接口

public class CollectiomEach {    public static void main(String[] args) {        Collection books = new HashSet();        books.add("a");        books.add("b");        books.add("c");        books.add("c");        books.forEach(obj->System.out.println(obj));        Iterator it = books.iterator();        while(it.hasNext()) {            String book = (String)it.next();           System.out.println(book);            }        it.forEachRemaining(obj->System.out.println(obj));        for(Object obj : books) {            String book = (String)obj;            System.out.println(book);        }    }}

1).使用Lambda遍历集合

1.Iterable接口有一个forEach(Consumer action)默认方法,该方法所需要的参数类型是一个函数式接口,Iterable接口是Collection接口的父接口。Consumer是一个函数式接口,因此可以使用Lambda表达式。

2).使用Iterator遍历集合元素

1.Iterator主要用于遍历(迭代访问)Collection集合元素中的,Iterator也被称为迭代器。必须依附于Collection对象。

2.当使用Iterator对集合进行迭代时是把集合元素的值传给迭代变量,所以修改迭代变量的值值对集合元素的值本身没有什么影响。

3.Iterator采用的是快速失败机制,一旦在迭代过程中检测到集合已经被修改,程序立即引发异常避免共享资源而引发的潜在问题。

3).使用Iterator表达式遍历Iterator

Iterator增加一个forEachREmaining(Consumer action)方法,该方法所需的Consumer参数同样是函数式接口

public class IteratorTest {    public static void main() {        Collection books = new HashSet();        books.add("a");        books.add("b");        books.add("c");        books.add("c");        Iterator it = books.iterator();        while(it.hasNext()) {            String book = (String)it.next();            System.out.println(book);            }        it.forEachRemaining(obj->System.out.println(obj));    }}

4).使用foreach遍历集合元素

5).使用Predicate操作集合

Collection集合的removeIf(Predicate filter)方法,改方法会批量删除符合filter条件的所有元素。该方法需要一个Predicate对象作为参数,Predicate也是函数式接口。

6).使用Stream操作集合

三.Set集合

set集合不允许包含相同元素的,如添加会返回false。

1).HashSet类

1.HashSet按HashSet算法来存储集合中的元素,因此具有较好的存取和查找性能。

2.不能保证元素的排列顺序,顺序可能与添加的顺序不同,HashSet不是同步的,如果多个线程同时访问一个HashSet,必须通过代码来保证其同步,集合元素可以是null。

3.HashSet会调用对象的HashCode方法得到该对象hashCode,决定其存储存储位置。如果两个元素通过equals比较返回true但他们的hashCode方法返回值不相等,HashSet将会把他们存储在不同的位置。就是说Hash判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode方法返回值也相等。

4.当把一个对象放入HashSet如果需要重写该对象的equals方法也应重写其hashCode方法。如果两个对象的equals返回true但对象的hashCode不同时依旧保存在不同的位置,如果两个对象的hashCode相同当他们的equals返回false时,这个位置会使用链式结构保存多个对象,HashSet访问集合元素时也是通过元素的hashCode来快速定位。

5.重写hashCode方法的基本原则:同一个对象多次调用应返回相同的值,通过equals返回相同的值hashCode也应返回相同的值。对象中用作equals方法比较标准的实例变量都应该用于计算hashCode值。

6.当程序把可变对象添加到HashSet之后,尽量不要去修改这些集合元素中参与hashCode,equals的实例变量,否则将会导致HashSet无法正确操作这些集合元素。

class A{    public boolean equals(Object obj) {        return true;    }}class B{    public int hashCode() {        return 1;    }}class C{    public int hashCode() {        return 2;    }    public boolean equals() {        return true;    }}public class HashSetTest {    public static void main(String[] args) {        //无序,按hashcode排列,不重复        HashSet books = new HashSet();        books.add(new A());        books.add(new A());        books.add(new B());        books.add(new B());        books.add(new C());        books.add(new C());        System.out.println(books);        }}

2).LinkedHashSet

LinkedHashSet集合也是根据hashCode值来决定元素的存储位置,但它同时使用链表维护元素的次序,使得元素以插入的顺序保存。

public class LinkedHasdSetTest {    public static void main (String[] args) {        //有序按hashcode排,不重复        LinkedHashSet<String> books = new LinkedHashSet<>();        books.add("疯狂java");        books.add("轻量级");        System.out.println(books);        books.remove("疯狂java");        System.out.println(books);        books.add("疯狂java");        System.out.println(books);    }}

 3).TreeSet类

TreeSet是SortSet接口的实现类,TreeSet确保集合元素处于排序状态,TreeSet不是根据元素的插入顺序进行排序的,而是根据元素的实际值的大小进行排序,TreeSet采用红黑树的数据结构来存储,TreeSet支持两种排序方法:

1.自然排序,集合元素按升序排序就是自然排序,如果试图把一个对象添加到TreeSet,则盖对象的类必须实现Comparable接口,否则程序抛出异常。除此之外,TreeSet只能添加同一种类型的对象。

2.定制排序:TreeSet可以通过Comparator接口的帮助,包含一个int compare()方法用于比较大小,返回正整数前者大,返回0一样大,返回负整数前者小。

如果需要实现定制排序,则需要在创建TreeSet集合对象的提供一个Comparable对象与该对象TreeSet集合关联,由Comparable负责集合元素的排序逻辑,Comparable是一个函数式接口,可以使用Lambda表达式。

import java.util.TreeSet;class M{    int age;    public M(int age) {        this.age = age;    }    public String toString() {        return ""+age;    }}public class TreeSetTest {    public static void main(String[] args) {        //按元素实际值大小处于排序状态,默认是自然排序        TreeSet nums = new TreeSet();        nums.add(5);        nums.add(2);        nums.add(10);        nums.add(-9);        System.out.println(nums);        System.out.println(nums.first());        System.out.println(nums.last());        TreeSet ts = new TreeSet( (o1 , o2) -> {             M m1 = (M)o1;             M m2 = (M)o2;             return m1.age > m2.age ? -1 : m1.age < m2.age ? 1 :0;        });        ts.add(new M(5));        ts.add(new M(6));        ts.add(new M(0));        ts.add(new M(4));        System.out.println(ts);    }}

4).EnumSet类

1.EnumSet所有元素必须是指定枚举类型的枚举类,该枚举类型在创建EnumSet时显式或隐式的指定,EnumSet集合元素以枚举值在enum定义的顺序来决定集合元素的排列顺序。EnumSet类没有暴露任何的构造器来创建该类的实例程序通过它的类方法来创建EnumSet对象。

5).HashSet 的性能总是比TreeSet好(特别是添加,查询元素操作),只有当需要一个保持排序的Set时,才使用TreeSet.LinkedHashSet遍历更快。HashSet,TreeSet,EnumSet都是线程不安全的如果有多个线程访问并修改,通常可以用Collections工具类方法来包装Set集合。

四.List集合

List集合代表一个有序,可重复的集合,集合每个元素都有其对应的顺序索引,List默认按元素的添加顺序设置元素的索引,第一个元素的索引为0.List判断两个元素相等的标准是只要通过equals方法比较返回true。List将会调用对象的equals方法依次与集合元素进行比较,如果equals方法以某个元素作为参数时返回true,List将会删除该元素。

public class ListTest {    public static void main(String[] args) {        //有序可重复,顺序为默认添加的顺序,判断相等为equals        List books = new ArrayList();        books.add("new");        books.add("java");        books.add("Android");        System.out.println(books);        books.add(2, "hello");        for(int i = 0;i < books.size();i++) {            System.out.println(books.get(i));        }        //固定长度的List        List fixedList = Arrays.asList("java","Android");        //获取fixedList的实现类class java.util.Arrays$ArrayList        System.out.println(fixedList.getClass());        //使用方法引用遍历集合数组        fixedList.forEach(System.out::println);    }}

1).ArrayList和Vector实现类

1.ArrayList和Vector都是基于数组实现的List类,ArrayList和Vector封装了一个动态的允许再分配的Object[]数组。ArrayList是线程不安全的,必须手动保证集合的同步性。

2).固定长度的List

Arrays是一个操作数组的工具类,提供了一个asList()方法,可以把一个数组或者指定个数的对象换成一个List集合,这个集合是Arrays的内部类的ArraList的实例。Arrays.ArrayList是一个固定长度的List集合程序只能访问集合里的元素,不可增加删除盖集合里的元素。

五.Queue集合

Queue用于模拟队列这种数据结构,队列通常指先进先出,队列的头部保存队列中存放时间最长的元素,队列的尾部保存时间最短的元素,新元素插入队列的尾部,访问元素会访问队列头部的元素,队列不允许随机访问队列中的元素。

1).PriorityQueue实现类

PriorityQueue是一个比较标准的队列实现类,PriorityQueue保存队列元素的顺序是按队列元素的大小进行重新排序。PriorityQueue不允许插入null元素,它还需要队列元素进行排序。(自然排序,定制排序)

public class PriorityQueueTest {    public static void main(String[] args) {        //队列:先进先出,保存队列的元素的顺序按加入队列的顺序的大小重新排序        //可能受到toString返回值的影响        PriorityQueue pq = new PriorityQueue();        pq.offer(6);        pq.offer(-3);        pq.offer(20);        pq.offer(18);        System.out.println(pq);        System.out.println(pq.poll());    }}

2).Deque接口与ArrayDeque实现类

Deque接口是Queue接口的子接口,代表一个双端队列,

ArrayList和ArrayDeque底层都采用一个动态的,可重新分配的Object[]数组来存储元素,当集合超出该数组的容量时,系统会重新分配一个数组。

当程序需要使用栈这种数据结构时推荐使用ArrayDeque。

3).LinkedList实现类

LinkedList是List接口实现类,可以根据索引随机访问集合中的元素,Linked还实现了Deque接口,可以被当作双端队列来使用因此既可以被当作栈来使用,也可以被当作队列来使用。

public class LinkedListTest {    public static void main(String[] args) {        //可作为List集合,双端队列,栈的用法        LinkedList books = new LinkedList();        books.add("疯狂java讲义");        books.add("轻量级java");        books.add("疯狂Android");        //加入队列的尾部        books.offer("队尾");        //加入栈的顶部        books.push("栈顶");        //加入队列的头部(相当于栈))        books.offerFirst("队列的头部");        for(int i = 0 ; i < books.size(); i++) {            System.out.println(books.get(i));        }        System.out.println(books.peekFirst());        System.out.println(books.pop());        System.out.println(books);    }}

1.ArrayList,ArrayDeque内部以数组形势来保存集合中的元素,随机访问有较好的性能,LinkedList内部以链表的形式插入,删除元素性能较好。

4).各种线性表的分析

List是一个线性表接口,ArrayList,LinkedList是基于数组的线性表和基于链表的线性表。Queue代表队列,Deque代表双队列(既可以作为队列使用,也可以作为栈使用)

如果需要遍历List集合元素,ArrayList,Vector应该使用随机方法get来遍历集合元素,LinkedList集合则应该采用迭代器Iterator。如果需要插入删除操作,可以考虑使用LinkedList。

3 六.Map集合

Map集合用于保存具有映射关系的数据,Key和value可以任何引用类型的数据。key不允许重复,如果添加key——value对时Map中已有重复的key,那么添加的value会覆盖该key原来的value。

程序可先调用Map集合的keySet获取所有的key,然后使用foreach循环遍历Map的所有的key,根据key可遍历所有的value。

1).HashMap和Hashtable实现类

1.Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的,所以HashMap比Hashtable性能更高一点。

2.Hashtable不允许使用null作为key和value,如果试图使用null放进Hashtable,将会引发异常,但是HashMap可以使用null作为key或value。

3.HashSet集合不能保证元素的顺序一样,HashMap,Hashtable也不能保证key——value的顺序,判断来两个key相等的标准是两个key通过equals()方法返回true两个key的hashCode一样。value判断两个value相等的标准是equals()方法比较返回true。如果使用可变对象作为HashMap,Hashtable的key,并且程序修改了作为key的可变对象,可能出现程序无法准确访问到Map中被修改的key。

2).LinkedHashMap实现类

LinkedHashMap也使用双向链表来维护key——value的次序,该链表负责维护Map的迭代顺序与key——value插入顺序保持一致。LinkedHahsMap可以避免对key——value进行排序,只要插入key-value时保持顺序即可。

3).SortedMap接口与TreeMap实现类

TreeMap就是一个红黑树数据结构,每个TreeMap作为红黑树的一个节点,Tree存储需要根据key对节点进行排序。

4).WeakHashMap实现类

Hashkey保留了对实际对象的引用的强引用,意味着只要该对象不被销毁,所有key引用的对象就不会被垃圾回收。HashMap也不会自动删除这些key所对应的key——value引用。WeakHashMap只保留了对实际对象的弱引用。

5).IdentityhashMap实现类。

当且仅当两个Key严格相等(key1 == key2)才认为两个key相等

6).EnumMap实现类

EnumMap是一个与枚举一起使用的Map实现,EnumMap中的key都必须是单个枚举类的枚举值,创建EnumMap必须显示或隐式指定他对应的枚举类.

7).各Map实现类的分析

TreeMap:总是处于有序状态,无序专门进行排序,当TreeMap被填充之后就可以调用keyset取得key组成的set,然后使用toArrary方法生成key的数组,接下来使用Arrays的binarySearch()方法在已排序的数组中快速的查询对象。

八.操作集合的工具类:Collections

Collections提供了大量方法对集合元素进行排序查询修改等操作。

1.同步控制:Collections类中提供了方法可以将指定集合包装成线程同步的集合,从而解决多线程并发访集合的线程安全问题。

2.提供了一些方法设置不可变集合。

原创粉丝点击