Collection集合常用方法
boolean add(E e); //向集合中添加元素
boolean remove(E e); //删除集合中的某个元素
void clear(); //清空集合中所有元素
boolean contains(E e); //判断集合中是否包含某个元素
boolean isEmpty(); //判断集合是否为空
int size(); //获取集合的长度
Object[] toArray(); //将集合转换成一个数组
迭代器
Collection集合元素的通用获取方式。在取元素前要判断集合中有没有元素。
使用集合中的方法iterator()
获取迭代器的实现类对象
Iterator 接口包含4个方法
public interface Iterator<E> {
E next();
boolean hasNext();
void remove();
default void forEachRemaining(Consumer<? super E> action);
}
应该将Java迭代器认为是位于两个元素之间,调用next时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用。但是到达集合末尾,next方法会抛出NosuchElementException
。因此,需要在调用next方法前调用hasNext方法,返回true时调用next方法。remove方法会删除上次调用next方法时返回的元素,例如若要删除两个相邻元素,必须先调用next方法。
iterator.remove();
iterator.next();
iterator.remove();
List接口
特点:
- 有序的集合
- 允许存储相同的元素
- 有索引,可以使用for循环遍历
ArrayList
特点:底层是数组实现的,查询快,增删慢。
LinkedList
特点:底层是链表实现的,查询慢,增删快。
在Java程序设计语言中,所有的链表实际上都是双向链接的。
数组和数组列表都有一个重大的缺陷:想要从中间位置删除一个元素要付出很大的代价,其原因是删除中间元素后,其后的所有元素都要向前端移动。插入一个元素也是如此。
链表解决了这个问题
元素删除与上述一致,这里需要说明的是,为了实现在任意位置添加元素,集合类库提供了子接口ListIterator
,其中包含了add方法,与Collection.add
不同,这个方法不返回boolean类型的值,它假定添加操作总会改变链表。add方法会在迭代器位置之前添加一个新对象。
另外,ListIterator
接口有两个方法,可以用来反向遍历链表:
E previous();
boolean hasPrevious();
与next方法一样,previous方法返回越过的对象。
通过一下代码示例来说明:
LinkedList<String> staff = new LinkedList<>();
staff.add("Amy");
staff.add("Bob");
staff.add("Carl");
ListIterator<String> iterator = staff.listIterator();
iterator.next();
iterator.add("Juliet");
iterator.previous();
iterator.remove();
最后的remove方法将刚刚添加进去的“Juliet”删除了,同样是删除previous越过的元素。
简而言之:add方法只依赖于迭代器的位置,而remove方法依赖于迭代器的状态
最后还有set方法,用一个新的元素取代调用next或previous方法返回的上一个元素。
多个迭代器的使用:
如果迭代器发现它的集合被另一个迭代器修改了,或是被该集合自身的方法修改了,救会抛出一个ConcurrentModificationException
异常。例如:
List<String> list = ...;
ListIterator<String> iter1 = list.listIterator();
ListIterator<String> iter2 = list.listIterator();
iter1.next();
iter1.remove();
iter2.next();// throws ConcurrentModificationException
为了避免并发修改的异常,可以遵循下述规则:可以给容器附加许多的迭代器,但这些只能读取列表。再单独附加一个既能读又能写的迭代器
常用方法:
void addFirst(E e); //将指定元素插入到链表的头部
void addLast(E e); //将指定元素插入到链表的尾部
void getFirst();
void getLast();
E removeFirst();
E removeLast(); //移除并返回
链表也有get方法根据索引来获取元素,但效率很低,如果要随机访问,就不应该使用链表。
Set接口
特点:
- 不允许存储重复的元素
- 没用索引(不能使用普通的for循环遍历)
HashSet
特点:底层是哈希表+(红黑树)实现的,无索引,不可以存储重复元素,存取无序。
构造函数:
HashSet(); //构造一个空散列表,默认容量16,装填因子0.75
HashSet(Collection<? extends E> elements); //构造一个散列集,将集合中的元素加到其中
HashSet(int initialCapacity); //构造一个空的具有指定容量的散列集
HashSet(int initialCapacity, float loadFactor); //装填因子(0.0-1.0)
Capacity
如果想要控制散列表的运行性能,就要指定一个初始的桶数(容量)。桶数是指用于收集具有相同散列值的桶的数目。(散列值与桶的总数取余,所得到的结果就是保存这个元素桶的索引,例如,某个对象的散列值为76268,并且有128个桶,对象就保存在76268%128 = 108号桶中)。通常将桶数设置为预计元素个数的75%-150%。参数initialCapacity是2的幂,默认16,例如,及时设置为5,也会被改成8
load factor
如果散列表太满,就需要再散列(rehashed):创建一个桶数更多的表,并将所有元素插入到这个新表中,然后丢弃原来的表。装填因子(load factor)决定何时进行再散列,例如,为0.75(默认值),那么表中超过75%的位置已经填入元素,这个表就会用双倍的桶数进行再散列。
hashCode
如果自定义类,就要负责实现这个类的hashCode
方法,自己实现的hashCode
方法应该与equals方法兼容,即如果a.equals(b)
为true,则a,b必须具有相同的散列码。
LinkedHashSet
特点:底层是哈希表+链表实现的,无索引、不可以存储重复元素、可以保证存取顺序
TreeSet
特点:底层是二叉树实现,一般用于排序
注意:由于每次插入元素时,都会被放在正确的排序位置上,放入树集的元素必须实现Comparable
接口,或者构造集时必须提供一个Comparator
Queue&Deque接口
特点:
- 可以在尾部添加一个元素,在头部删除一个元素
- 不支持在队列中间添加元素
- 双端队列可以在头部尾部同时添加或删除元素
常用方法:
java.util.Queue<E>
boolean offer(E element); //将元素添加到尾端,如果队列满了,返回false
E poll(); //删除并返回队列头部的元素,队列为空则返回null
E peak(); //返回队列头部元素(不删除),为空则返回null
//与上述三个方法类似的有add(),remove()和element方法,但失败都会抛出异常
java.util.Deque<E>
boolean offerFirst(E element); //添加到头部
boolean offerLast(E element); //添加到尾部
E pollFirst();
E pollLast();
E peakFirst();
E peakLast();
PriorityQueue
特点:
- 按任意顺序插入,按特定顺序检索(无论何时调用remove方法,都会获得队列中最小的元素)
- 堆数据结构
- 元素要实现
Comparable
接口,或者构造时必须提供一个Comparator
Map集合
特点:
- 存放键/值对,通过唯一的键查找值
常用方法:
V get(Object key); //返回与键对应的对象,如果没有则返回null
default V getOrDefault(Object key,V defaultValue); //如果没有则返回这个默认值
V put(K key, V value); //存放键值对,如果键已经存在则覆盖值,返回原有的值
void putAll(Map<? extends K, ? extends V> entries); //放入给定映射中的所有条目
boolean containsKey(Object key);
boolean containsValue(Object value);
default void forEach(BiConsumer<? super K,? super V> action);
//对所有键值对执行这个动作,可以使用lamda表达式
HashMap
特点:
- 允许存入null键,null值(null值只有一个,并存于数组第一个位置)
- 无序集合,而且顺序会随着元素的添加而随时改变(添加顺序,迭代顺序不一致)
- 随着元素的增加而动态扩容(与ArrayList原理一致)
- 不存在重复元素(得益于hashCode算法和equals方法)
- 线程不安全
TreeMap
特点:
- 不允许出现重复的key
- 可以插入null键,null值
- 可以对元素进行排序
- 无序集合(插入和遍历顺序不一致)
未完待续…