集合梳理
概述
- 集合框架是高性能的
- 动态数组,链表,树,哈希表的实现是高效率的
- 算法是集合机制的另一个特性Collections中的静态方法,所有集合都可以使用,为操作集合提供了标准
- iterator 遍历迭代集合
- spliterator java8新增的并行迭代器
- 泛型在根本上改变了集合
- 自动拆装箱使基本类型使用更加方便
- list 有序可重复集合,set 无序不可重复集合
接口
Iterable
|__Colleaction
|__List
|__Set
| |__SortedSet
| |__NavigableSet
|__Queue
|__Deque
Collection 集合框架的基础
封装了集合操作的基本算法
比如add,addAll,contains,containsAll等
List接口
/**
* list add
*/
@Test
public void test2() {
List<Integer> list = new ArrayList<>();
//插入列表中指定的索引位置但是需要知道index 是否越界
//IndexOutOfBoundsException
list.add(10,5);
System.out.println(list);
}
/**
* ListIterator 迭代器
* 双向遍历
* 添加元素
* 功能更加强大
*/
@Test
public void test3() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(10);
ListIterator<Integer> listItera = list.listIterator();
while(listItera.hasNext()) {
System.out.println(listItera.next());
}
}
/**
*移除元素
*remove
*有两个重载函数
*移除元素的时候只能移除第一个相同的元素
*
*removeIf 根据条件进行删除,移除所有的函数
*/
@Test
public void test4() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(20);
System.out.println(list);
list.remove(1);
System.out.println(list);
List<String> strs = new ArrayList<>();
strs.add("A");
strs.add("B");
strs.add("A");
strs.add("B");
System.out.println(strs);
strs.remove("A");
System.out.println(strs);
//根据条件进行删除
strs.removeIf(e->e.equals("B"));
System.out.println(strs);
}
/**
* set 更改指定位置上面的额值
*/
@Test
public void test5() {
List<String> list = new ArrayList<>();
list.add("A");
list.add("C");
System.out.println(list);
list.set(1, "D");
System.out.println(list);
}
/**
* 截取字符串
*/
@Test
public void test6() {
List<Integer> list = new ArrayList<>();
for(int i=0;i<10;i++)
list.add(i);
List<Integer> list1 = list.subList(4, 8);
System.out.println(list1);
list1.set(2, 0);
System.out.println(list1);
System.out.println(list);
/**
* 从输出结果可以看出并没有产生一个新的数组,还以引用的老数组中的元素地址
* [4, 5, 6, 7]
[4, 5, 0, 7]
[0, 1, 2, 3, 4, 5, 0, 7, 8, 9]
*/
}
set接口
set不允许集合中有重复的元素,当add重复元素时会返回false.set没有定义自己的一些方法
SortedSet 以升序进行排序
@Test
public void test7() {
SortedSet<Integer> sort = new TreeSet<>();
sort.add(100);
sort.add(10);
sort.add(80);
sort.add(1);
System.out.println(sort);
//[1, 10, 80, 100]
}
自定义排序规则
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
};
SortedSet<Integer> sort = new TreeSet<>(com);
sort.add(100);
sort.add(10);
sort.add(80);
sort.add(1);
System.out.println(sort);
Comparator<? super Integer> comparator = sort.comparator();
System.out.println(comparator);
//[100, 80, 10, 1]
//collection.Maintest$1@2077d4de
其他api操作
SortedSet<Integer> sort = new TreeSet<>();
sort.add((int)(Math.random()*100));
sort.add((int)(Math.random()*100));
sort.add((int)(Math.random()*100));
sort.add((int)(Math.random()*100));
sort.add((int)(Math.random()*100));
sort.add((int)(Math.random()*100));
System.out.println("集合" + sort);
//第一个元素
System.out.println("第一个元素" + sort.first());
//最后一个元素
System.out.println("最后一个元素"+sort.last());
//返回小于某个值的数组集合
System.out.println("返回小于某个值的数组集合"+sort.headSet(50));
System.out.println(sort.headSet(10));
//返回某两个值区间的元素
System.out.println("返回某两个值区间的元素"+sort.subSet(50,60));
//返回大于某个值的元素
System.out.println("返回大于某个值的元素"+sort.tailSet(50));
//输出:
//集合[16, 41, 44, 48, 67, 90]
//第一个元素16
//最后一个元素90
//返回小于某个值的数组集合[16, 41, 44, 48]
//[]
//返回某两个值区间的元素[]
//返回大于某个值的元素[67, 90]
NavigableSet
/**
* NavigableSet接口
* 扩展了SortSet 接口
* 具体使用可以查看APi
*/
@Test
public void test10() {
NavigableSet<Integer> navigableSet = new TreeSet<>();
navigableSet.add(100);
navigableSet.add(20);
navigableSet.add(80);
navigableSet.add(5);
System.out.println("自动排序结果:"+navigableSet);
Integer num = navigableSet.ceiling(10);
System.out.println("大于等于值得最小元素:"+num);
//自动排序结果:[5, 20, 80, 100]
//大于等于值得最小元素:20
}
Queue
队列接口通常是基于先进先出的准则
- 只能在队列的头部移除元素
- 有两个方法移除元素poll和remove 如果队列为空,一个返回null.一个抛出异常,poll可以获取到元素并删除
- elenment和peek也可以获取到元素但是不会删除元素,这两个的区别是,如果队列为空,element会抛出异常,peek返回null
- offer 向队列中添加元素,但是如果队列固定长度会添加失败
Deque
扩展了Queue接口 既可以像标准队列一样先进先出,也可以像堆栈一样后进先出
- 提供了push 和pop的方法,使其功能和堆栈类似
- 具体请查看api
集合类
ArrayList
-
动态数组,动态的增加或者减少长度
-
如果事先知道长度可以通过ensureCapacity设定好数组的长度,避免重读的分配内存,提高性能
-
T[] toArray(T[] t)转为数组,还有一个是转为Object[]
ArrayList<String> list = new ArrayList<>(); list.ensureCapacity(10); System.out.println("集合长度" + list.size()); list.add("A"); list.add("B"); list.add("C"); list.add("D"); list.add("E"); System.out.println("集合长度" + list.size()); System.out.println(list); list.add("F"); System.out.println("集合长度" + list.size()); System.out.println(list); //trimToSize精确地等于当前集合元素的数量 list.trimToSize(); //生成一个新的数组 String[] strs = new String[list.size()]; list.toArray(strs); for(String s : strs){ System.out.printf("%s ",s); } System.out.println(); strs[0] = "ASD"; System.out.println(list); for(String s : strs){ System.out.printf("%s ",s); } System.out.println();
LinkedList
-
实现了list Deque Queue接口
-
提供了链表的数据结构
LinkedList<String> list = new LinkedList<>(); list.add("A"); list.add("B"); list.add("C"); list.add("D"); list.add("E"); list.addFirst("first"); list.addLast("last"); System.out.println(list); list.add(1,"A@"); System.out.println(list); list.remove("B"); //移除只移除第一个,如果后面还有B 则不进行移除 list.remove(4); System.out.println(list); /* [first, A, B, C, D, E, last] [first, A@, A, B, C, D, E, last] [first, A@, A, C, E, last]*/
HashSet
-
实现了set接口
-
创建使用哈希表存储元素的集合
-
不能保证元素的顺序
-
TreeSet可以有序的存储
HashSet<String> list = new HashSet<>(); list.add("manduan"); list.add("baian"); list.add("pingan"); list.add("A"); list.add("SS"); System.out.println(list); //[SS, A, manduan, baian, pingan]
linkedHashSet
-
扩展了HashSet
-
维护了一个链表,可以保证插入的顺序
LinkedHashSet<String> list = new LinkedHashSet<>(); list.add("manduan"); list.add("baian"); list.add("pingan"); list.add("A"); list.add("SS"); System.out.println(list); //[manduan, baian, pingan, A, SS]
TreeSet
-
实现了 NavigableSet
-
以升序进行存储
-
访问检索速度快
-
大容量,快速查找到有序的信息最好的选择
TreeSet<String> list = new TreeSet<>(); list.add("北京"); list.add("上"); list.add("江苏"); list.add("南京"); //根据unicode编码进行排序 System.out.println(list); System.out.println(list.subSet("B", "是")); //[上, 北京, 南京, 江苏] //[上, 北京, 南京]
PriorityQueue
-
可以指定比较器 comparator 。当不指定比较器的时候默认采用升序的方式
PriorityQueue<Integer> pq = new PriorityQueue<>(); pq.add(100); pq.add(10); pq.add(40); System.out.println(pq); pq.offer(20); pq.offer(2); System.out.println(pq); while(pq.size()>0) { System.out.println(pq.poll()); }
ArrayDeque
-
动态数组,双端队列
-
实现了Deque接口没有添加自己的方法
Deque<String> list = new ArrayDeque<>(); list.add("A"); list.offer("B"); list.addFirst("First"); list.addLast("last"); System.out.println(list); System.out.println("取走第一个:"+ list.getFirst()); System.out.println("取走最后一个:"+list.getLast()); while(list.peek() !=null) { System.out.println("第一个:"+list.pollFirst()); System.out.println("最后一个:"+list.pollLast()); }
EnumSet
- 实现set接口
- 专用于枚举类型
Iterator ListIterator 迭代器访问集合
- 先获取迭代器
- 对于实现list接口的集合可以使用ListIterator
- ListIterator 可以用set方法更改元素值
- hasPrevious反向遍历
代码示例
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
list.add("F");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()) {
String ele = iterator.next();
System.out.print(ele + " ");
}
System.out.println();
ListIterator<String> li = list.listIterator();
while(li.hasNext()) {
String ele = li.next();
li.set(ele + "+");
}
iterator = list.iterator();
while(iterator.hasNext()) {
String ele = iterator.next();
System.out.print(ele + " ");
}
System.out.println();
while(li.hasPrevious()) {
String ele = li.previous();
System.out.print(ele + " ");
}
System.out.println();
//A B C D E F
// A+ B+ C+ D+ E+ F+
//F+ E+ D+ C+ B+ A+
for-each
-
不修改元素
-
不反向获取元素
List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); Integer sum = 0; for(Integer i:list) { sum += i; } System.out.println(sum);
Spliterator 并行迭代器
List<Integer> list = new ArrayList<>();
while(list.size() <100) {
list.add((int)(Math.random() * 100));
}
System.out.println(list);
Spliterator<Integer> spliterator = list.spliterator();
System.out.println("spliterator的特征:" + spliterator.characteristics());
System.out.println("返回剩余需要遍历的元素个数:"+ spliterator.estimateSize());
/* spliterator.forEachRemaining((e)->{
//System.out.println("元素:" + e);
});*/
System.out.println("剩余:" + spliterator.estimateSize());
//未被排序返回 IllegalStateException 异常
// System.out.println("排序规则:" + spliterator.getComparator().getClass().getName());
System.out.println("剩余要遍历的元素个数:"+spliterator.getExactSizeIfKnown());
while(spliterator.tryAdvance((e)->e = e*10));
映射接口
Map
compute
default V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction)
示例
Map<String,Object> map = new HashMap<String, Object>();
map.put("k1", "k1val");
map.put("k2", 100);
map.put("k3", 3.1415926);
map.compute("k1", (e,u)-> {
System.out.println(u);
if(u.equals("k1val")) {
return "k1new";
}
return null;
});
System.out.println(map);
map.compute("k4", (e,u)->{
return "k4val";
});
System.out.println(map);
//compute 第一个参数是key 第二个参数是函数,返回null 删除元素,返回值如果有key就替换反之增加
输出
k1val
{k1=k1new, k2=100, k3=3.1415926}
{k1=k1new, k2=100, k3=3.1415926, k4=k4val}
computeIfAbsent key存在的时候不会执行
Map<String,Object> map = new HashMap<String, Object>();
map.put("k1", "k1val");
map.put("k2", 100);
map.put("k3", 3.1415926);
System.out.println(map);
map.computeIfAbsent("k4", (e)->{
System.out.println(e);
return "k4val";
});
System.out.println(map);
//只有key存在的时候不会执行
map.computeIfAbsent("k1", (e)->{
System.out.println(e);
return "k1val-new";
});
System.out.println(map);
输出
{k1=k1val, k2=100, k3=3.1415926}
k4
{k1=k1val, k2=100, k3=3.1415926, k4=k4val}
{k1=k1val, k2=100, k3=3.1415926, k4=k4val}
computeIfPresent key不存在的时候不会执行
Map<String,Object> map = new HashMap<String, Object>();
map.put("k1", "k1val");
map.put("k2", 100);
map.put("k3", 3.1415926);
map.computeIfPresent("k1", (e,v)->{
return "k1-val-new";
});
System.out.println(map);
//只有key不存在的时候才会执行
map.computeIfPresent("k4", (e,u)->{
return "k4-val";
});
System.out.println(map);
输出
{k1=k1-val-new, k2=100, k3=3.1415926}
{k1=k1-val-new, k2=100, k3=3.1415926}
其他api
Map<String,Object> map = new HashMap<String, Object>();
map.put("k1", "k1val");
map.put("k2", 100);
map.put("k3", 3.1415926);
System.out.println("是否包含某个key:"+map.containsKey("k1"));
System.out.println("是否包含某个value:"+map.containsValue(100));
Map<String,Object> map1 = new HashMap<String, Object>();
map1.put("k1", "k1val");
map1.put("k2", 100);
map1.put("k3", 3.1415926);
System.out.println("两个map是否一样:" + map.equals(map1));
map.forEach((k,v)->{
System.out.println(k + "\t" + v);
});
//如果有就返回
System.out.println("没有就返回后面的:" + map.getOrDefault("k4", "k4val"));
System.out.println("如果有就返回:" + map.getOrDefault("k3", "k3val"));
System.out.println("是否为空:"+map.isEmpty());
System.out.println("长度:" + map.size());
输出
是否包含某个key:true
是否包含某个value:true
两个map是否一样:true
k1 k1val
k2 100
k3 3.1415926
没有就返回后面的:k4val
如果有就返回:3.1415926
是否为空:false
长度:3
###merge
Map<String,Object> map = new HashMap<String, Object>();
map.put(“k1”, “k1val”);
map.put(“k2”, 100);
map.put(“k3”, 3.1415926);
//如果不存在key不会执行后面的函数,但是会进行赋值
map.merge("k4", "k4-val", (k,v)->{
return "k4-val-new";
});
System.out.println(map);
//如果存在就会执行后面的函数,执行赋值
map.merge("k1", "k4-val", (k,v)->{
return "k4-val-new";
});
System.out.println(map);
putIfAbsent
Map<String,Object> map = new HashMap<String, Object>();
map.put("k1", "k1val");
map.put("k2", 100);
map.put("k3", 3.1415926);
map.put("k4", null);
/**
* 如果没有值就会替换,或者添加
* 如果有值不为null就不会替换
*/
System.out.println(map.putIfAbsent("k5", "k5-val"));
System.out.println(map.putIfAbsent("k4", "k4-val-new"));
System.out.println(map.putIfAbsent("k1", "k1-val-new"));
System.out.println(map);
输出
null
null
k1val
{k1=k1val, k2=100, k3=3.1415926, k4=k4-val-new, k5=k5-val}
remove
Map<String,Object> map = new HashMap<String, Object>();
map.put("k1", "k1val");
map.put("k2", 100);
map.put("k3", 3.1415926);
map.remove("k1");
map.remove("k4", 100);
map.remove("k2","100");
System.out.println(map);
SortedMap 扩展了Map
其中通过父集合获取子集合的改变值会影响其他集合因为引用的地址是一个
SortedMap<String, Object> map = new TreeMap<>();
map.put("k3", 3.1415926);
map.put("k1", "k1val");
map.put("k2", 100);
System.out.println(map);
Comparator<?> c = map.comparator();
//自然排序 输出 null
System.out.println(c);
System.out.println("返回第一个键:"+map.firstKey());
System.out.println("返回小于k3的所有值:" + map.headMap("k3"));
System.out.println("返回k1~k3的值(含头不含尾):" + map.subMap("k1", "k3"));
System.out.println("返回大于等于k2:"+map.tailMap("k2"));
System.out.println("返回最后一个:"+map.lastKey());
输出
{k1=k1val, k2=100, k3=3.1415926}
null
返回第一个键:k1
返回小于k3的所有值:{k1=k1val, k2=100}
返回k1~k3的值(含头不含尾):{k1=k1val, k2=100}
返回大于等于k2:{k2=100, k3=3.1415926}
返回最后一个:k3
NavigableMap 扩展丰富了 SortedMap
具体使用查看api列表。
Map.Entry
- 提供了映射条目的操作功能,具体使用不在叙述
##实现类概述 HashMap TreeMap
- hashmap 无序存储
- treeMap有序存储
- treemap 可以指定排序规则 TreeMap(Comparator comparator);
LinkedHashMap
1.维护了一个条目链表,按照插入的顺序进行迭代
Map<String,Object> map = new LinkedHashMap<String, Object>();
map.put("k1", "k1-val");
map.put("k3", 100);
map.put("k2", 3.1415);
map.forEach((k,v)->System.out.println(k + "\t" + v));
比较器 Comparator
//先定义倒叙排序
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
};
NavigableMap<String, Object> map = new TreeMap<>(comparator);
map.put("k1", "k1-val");
map.put("k3", 100);
map.put("k2", 3.1415);
System.out.println("默认倒叙排列:"+map);
//顺序翻转
comparator = comparator.reversed();
NavigableMap<String, Object> map1 = new TreeMap<>(comparator);
map1.putAll(map);
System.out.println("reversed翻转后排序:"+map1);
//获取非自然顺序排序
Comparator<String> comparator1 = Comparator.reverseOrder();
NavigableMap<String, Object> map2 = new TreeMap<>(comparator1);
map2.putAll(map);
System.out.println("自然顺序翻转的静态方法:" + map2);
//获取自然顺序排序
Comparator<String> comparator2 = Comparator.naturalOrder();
NavigableMap<String, Object> map3 = new TreeMap<>(comparator2);
map3.putAll(map);
System.out.println("自然顺序排序:"+ map3);
/**
* 处理null 在前面还是在后面
*/
//null在前面
Comparator<Integer> intComparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
};
Comparator<Integer> nullFirst = Comparator.nullsFirst(intComparator);
Set<Integer> list = new TreeSet<>(nullFirst);
list.add(100);
list.add(10);
list.add(30);
list.add(null);
list.add(50);
System.out.println("nul在前面" + list);
//null在后面
Comparator<Integer> nullAfter = Comparator.nullsLast(intComparator);
Set<Integer> list2 = new TreeSet<>(nullAfter);
list2.addAll(list);
System.out.println("nul在后面" + list2);
输出结果
默认倒叙排列:{k3=100, k2=3.1415, k1=k1-val}
reversed翻转后排序:{k1=k1-val, k2=3.1415, k3=100}
自然顺序翻转的静态方法:{k3=100, k2=3.1415, k1=k1-val}
自然顺序排序:{k1=k1-val, k2=3.1415, k3=100}
nul在前面[null, 10, 30, 50, 100]
nul在后面[10, 30, 50, 100, null]
thenComparing 两个比较器使用,先比较名字 再比较姓氏
Comparator<String> comaprator = (o1,o2)-> o1.compareToIgnoreCase(o2);
Comparator<String> comparator1 = comaprator.thenComparing((o1,o2)->o1.compareToIgnoreCase(o2));
TreeMap<String, Double> map = new TreeMap<>(comparator1);
map.put("John done", 200.12);
map.put("Tome Sime", 300.33);
map.put("Jane back", 20.0);
map.put("Tod hell", -10.1);
map.put("Ralh Smith", 99.3);
map.forEach((k,v)->System.out.println(k + "\t" + v));
输出
Jane back 20.0
John done 200.12
Ralh Smith 99.3
Tod hell -10.1
Tome Sime 300.33