本文记录Java集合学习笔记
目录1,Java集合类介绍
Java集合类介绍
Java集合类架构层次
Java集合类应用
Java集合类操作
集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类。相比数组,当需要保存一个可以动态增长的数据(在编译时无法确定具体的数量),java的集合类就是一个很好的设计方案了。
集合接口分为:Collection和Map。list、set实现了Collection接口
Collection和Map的区别在于容器中每个位置保存的元素个数:
Collection 每个位置只能保存一个元素(对象)
Map保存的是"键值对",就像一个小型数据库。我们可以通过"键"找到该键对应的"值"
2,Java集合类架构层次
3,Java集合类应用
1)Set
HashSet
equals()决定是否可以加入HashSet、而hashCode()决定存放的位置,它们两者必须同时满足才能允许一个新元素加入HashSet
如果两个对象的hashCode相同,但是它们的equlas返回值不同,HashSet会在这个位置用链式结构来保存多个对象。而HashSet访问集合元素时也是根据元素的HashCode值来快速定位的,这种链式结构会导致性能下降。
LinkedHashSet
HashSet的子类,根据元素的hashCode值来决定存放位置,同时使用链表维护元素的次序,看起来是以插入的顺序保存的,遍历时会按照添加顺序访问。
TreeSet
使用红黑树的数据结构来存储集合元素
1. 自然排序:
TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,根据红黑树结构找到它的存储位置,然后将集合元素按升序排序,即自然排序。如果试图把一个对象添加到TreeSet时,则该对象的类必须实现Comparable接口,否则程序会抛出异常。
如果两个对象通过compareTo(Object obj)方法比较相等,新对象将无法添加到TreeSet集合中(牢记Set是不允许重复的概念)。
2.定制排序:
在创建TreeSet集合对象时,提供一个函数式接口Comparator的对象与该TreeSet集合关联,负责集合元素的排序逻辑。
EnumSet
在内部以位向量的形式存储,以枚举值在Enum类内的定义顺序来决定集合元素的顺序。
各Set实现类的性能
1,只有当需要保持一个排序的Set时,才应该使用TreeSet,否则都应该使用性能总是比TreeSet好的HashSet。
2,LinkedHashSet对于普通的插入、删除操作比HashSet慢,但遍历更快。
3,EnumSet是所有Set中性能最好的,但只能保存同一个枚举类的枚举值作为集合元素。
4,这三个实现类都是线程不安全的,通常可以使用Collections工具类的synchronizeSortedSet方法来包装该Set集合,此操作最好在创建时进行。
2)List
有序,可重复,允许插入null对象,使用索引来访问指定位置的集合元素其判断两个对象只要通过equals()方法比较返回true即可。
List实现了Iterator接口的子接口ListIterator,在Iterator基础上增加了如下方法:
boolean hasPrevious()
Object previous()
void add(Object o):在指定位置插入一个元素
List另外提供了一个listIterator()方法,返回一个ListIterator对象。
ArrayList和Vector实现类
都是基于数组实现的List类,initialCapacity参数来设置该数组的长度,默认长度为10 。当添加大量元素时,可以使用ensureCapacity(int minCapacity)方法一次性增加initialCapacity大小,
void trimToSize():调整集合的Object[]数组长度为当前元素的个数,以减少占用的存储空间。
Vector是古老的集合,是线程安全的,但是具有很多缺点,应尽量避免使用。
即使需要保证LIst集合线程安全,也不推荐使用Vector,可以用Collections工具类包装ArrayList变成线程安全的。
Vector还有一个Stack子类,LIFO容器。也是一个古老的集合,需要栈结构时可以使用ArrayDeque代替。
3)Queue集合
Queue用于模拟队列这种数据结构,通常是FIFO容器,Queue接口只有一个PriorityQueue实现类,除此之外还有一个Deque接口,Deque代表一个双端队列,也可以当成栈来使用,Java为Deque提供了ArrayDeque和LinkedList实现类
PriorityQueue
时一个比较标准的队列实现类,其保存队列元素的顺序时按队列元素的大小进行重新排序。不允许插入null元素,排序方式有自然排序和定制排序,基本和TreeSet一致。
ArrayDeque
基于数组实现的双端队列,ArrayList和ArrayDeque两个集合类的实现机制基本相似创建Deque时同样可指定一个numElements参数,指定Object[]数组的长度;默认长度为16;
LinkedList
同时时List和Deque的实现类,和ArrayList、ArrayDeque完全不同,它内部是使用链表的形式来保存集合中的元素,因此随机访问性能较差,但在插入、删除元素时性能比较出色。总体上来说ArrayList性能比LinkedList要好,大部分时候都考虑使用ArrayList。
使用List集合的建议:
-如果需要遍历,对于ArrayList、Vector集合应该使用随机访问方法(get);对于LinkedList则更应使用迭代器(Iterator)。
-频繁插入、删除则考虑使用LinkedList,使用ArrayList、Vector集合需要经常重新分配内部数组。
-多线程访问可以考虑使用Collections将集合包装成线程安全的集合
注意:所有内部基于数组的集合实现,如ArrayList、ArrayDeque等,使用随机访问的性能比使用Iterator迭代访问的性能要好,因为随机访问会被映射称对数组元素的访问
4)Map
Map包含了一个keySet()方法,用于返回Map里所有kay组成的Set集合。
还提供了一个Entry内部类来封装kay-value对,而计算Entry存储时只考虑Entry封装的key。
HashMap和Hashtable
其两者关系完全类似于ArrayList和Vector,Hashtable不允许使用null作为key和value,HashMap不允许有key相同,所以只能有一对key-value的key为null(就像Set)。
LinkedHashMap
HashMap的子类,使用双向链表来维护key-value对的次序
Properties读写属性文件
Hashtable类的子类,其key和value都只能是字符串类型。相当于key、value都是String类型的Map;
SortedMap接口和TreeMap实现类,如SortedSet和treeSet一般
WeakHashMap实现类,和HashMap的用法基本相似,但是WeakHashMap的key只保留对实际对象的弱引用。
IdentityHashMap实现类
和HashMap基本相似,但是当且仅当两个key严格相等(key1 == key2)时,才认为两个key相等,对于普通的HashMap而言,只需要key通过equals()方法比较返回true,且它们的hashCode值相等即可
EnumMap实现类
在内部以数组形式保存,不允许null作为key,但可作为value。
一般使用HashMap,其正是为快速查询设计的,底层其实是采用数组来存储key-value对,但如果需要一个总是排好序的Map时,使用TreeMap。
4,Java集合类操作
使用Iterable遍历
Java 8为Collection的父接口Iterable接口新增了一个forEach(Consumer action)默认方法,Consumer是一个函数式接口,accept(T t)方法是该接口中唯一的抽象方法。
使用Iterator遍历
Iterator主要用于遍历Collection集合中的元素,Iterator对象也被称为迭代器。其定义了4个方法:
boolean hasNext()
Object next()
void remove()
void forEachRemaining(Consumer action)
Java 8为Iterator新增的forEachRemainin(Consumer action)方法所需的Consumer参数同样也是函数式接口。
当使用Iterator对集合元素进行迭代时,Iterator并不是把集合元素本身传给了迭代变量,而是把集合元素的值传给迭代变量,所以修改迭代变量的值对集合的元素本身没有任何影响。 并且迭代访问时,Collectio集合里的元素不能被改变,只有通过Iterator的remove()方法删除上一次next()方法返回的集合元素才可以;否则会引发java.util.concurrent.ModificationException异常。
使用Predicate 操作集合
Java 8为Collection集合新增了一个removeIf(Predicate filter)方法,该方法将会批量删除符合filter条件的所有元素,例如
collection.removeIf(ele -> ((Stirng)ele).length() < 10); //将删除长度小于10的字符串集合元素
使用Stream操作集合
Stream、IntStream、LongStream、DoubleStream等流式API,这些API代表多个支持串行和并行聚集操作的元素;
Java还为每个流式API提供了对应的Builder,可以使用对应的Builder来创建对应的流。
独立使用Stream的步骤如下:
-使用Stream的builder()类方法创建对应的Builder。
-重复调用Builder的add()方法向该流中添加多个元素。
-调用Builder的build()方法获取对应的Stream。
-调用Stream的聚集方法。
聚集方法分为
-中间方法(intermediate):中间操作允许流保持打开状态,可直接调用后续方法,中间方法返回的是另一个流;
-末端方法(terminal):末端方法是对流的最终操作,执行之后该流会被消耗,不再可用。
主要参考《疯狂Java讲义》,本人才疏学浅,如有错误烦请各位大佬指点
另外菜鸟的这篇教程通过接口,实现类,算法三个层次去分析集合,写的很不错。Java 集合框架菜鸟教程