公平不是留给你的,机会也是
前言
Java集合框架是Java的一套性能优良、使用方便的接口和类,方便我们存储和操作对象组。
是不是看完没啥感觉,那就往下看😜
一、集合框架设计原则
集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。
集合框架作为一套规范的体系结构,当然他们对外的表现也是有要求的,想男团一样,有着鲜明的特征(唱跳rap)。它的特征:
-
接口:集合的抽象数据类型。例如Collection、List、Set、Map等,定义成为接口,方便规范要求,多个接口是为了以不同的方式操作接口。
-
实现:接口的具体实现,实际上他们都是可以重复使用的数据结构(就像我们根据汽车的设计图造出来一台汽车,不能说我们开一次这个车就消失了,这事你能信?),例如ArrayList、HashSet等。
-
算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。
具备这些特征(接口、实现、算法),我们就离做idol不远了,当然想要出道还得满足以下的设计原则:
框架满足高性能,基本集合的实现是高效的;
允许不同类型的集合,以类似的方式工作,具有高度互相操作性;
集合的扩展和适应必须是简单的;
这样你就可以成为idol本豆了
二、Java集合框架图
网上引用的比较多的一张框架图,我们用这个图来学习;
仔细看图我们能够发现,Java集合框架主要包括两种类型的容器,集合(Collection)和 图(Map);集合存储的是元素集合,图存储的是键值对。
Collection和Map是Java集合框架的根接口,所有集合类都位于java.util包下。
Collection接口主要有三种类型的集合:Set、Queue、List;
Set代表无序不可重复的集合;
Queue代表一种队列集合;
List代表有序重复的集合;
这三种集合我们今后详细讲解;
Map接口我们需要学习她下面的HashMap、Hashtable、LinkedHashMap、SortedMap;
HashMap是由数组和链表这两个数据结构存储数据;
HashTable和HashMap一样,但他的函数都是同步的;
LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序;
SortedMap是按K进行升序排序;
三、Collection接口
Collection接口算是集合框架的顶层接口之一,继承于[Iterable接口],不能被实例化。
这里介绍一下Iterable接口,集合的顶级接口,没有之一。🛹
为什么要设计这样的一个接口?
咱们的Java是面向对象的,处理多个对象是常态,想要处理多个对象,你得想办法把对象放在一个地方统一处理,这就需要我们的容器–集合。有人可能想咱们不是有数组吗,为啥还用集合里?
因为数组功能比较单一,而且他的长度是从娘胎里面带出来的,从一出生就确定了他的高度,不想我们大家的潜力是无穷的。
Collection接口的抽象方法:
//添加功能
boolean add(Object o) //添加元素
boolean addAll(Collection c) //批量添加,添加一个集合的元素
//删除功能
void clear() //清空集合,移除所有元素
boolean remove(Object o) //移除元素,移除一个元素
boolean removeAll(Collection c) //批量移除,移除一个集合的元素,只要一个元素被移除了,就返回true
default boolean removeIf(Predicate<? super E> filter) {} // 删除集合中复合条件的元素,删除成功返回true
//判断功能
boolean contains(Object o) //是否包含在集合中,判断集合是否包含该元素
boolean containsAll(Collection c) //是否包含所有的元素,只有包含所有元素才叫包含
boolean isEmpty() //判断集合是否为空
boolean equals(Object o)//将指定的对象与此集合进行比较以获得相等性。
//获取功能
Iterator<E> iterator() // 获取迭代器
default Spliterator<E> spliterator() {} //获取可分割迭代器
default Stream<E> stream() {} //获取流
default Stream<E> parallelStream() {} //获取并行流
//交集功能
void retainAll(Collection c) // 移除在c中不存在的元素,移除此collection中未包含在指定collection中的所有元素。集合A和集合B做交集,最终的结果保存在集合A,返回值表示的是A是否发生过变化。
//长度功能
int size() //集合大小,返回元素的个数
//转换功能
Object[] toArray() // 转成数组
//hash获取
int hashCode() //返回此集合的哈希值
光看效果还是不太行,咱们现实碰一碰.
package wang.collection;
import java.util.ArrayList;
import java.util.Collection;
/**
* @version 1.0
* @auther WangCode
* @date 2021/2/27 22:22
*/
public class Test {
public static void main(String[] args) {
//创建Collection集合
Collection collection = new ArrayList<>();
//添加元素
collection.add("demo1");
collection.add("demo2");
collection.add(123456);
collection.add(true);
System.out.println(collection);
}
}
这里要注意的点是,如果你添加的是基本类型的数据,他会自动的给你装箱,变成引用类型添加到集合中去;
有图有真相(嘿嘿);
当然,在实际的开发过程中,一个集合存储的数据类型一般是唯一的,这个可以在定义集合的时候进行操作,通过泛型约束他的类型,这样我们的集合就不再那么的花心;
例如:
Collection<String> collection = new ArrayList<>();
下面是一些最基本的用法,这个东西需要自己敲出来去验证自己的想法,别人说的不一定都是对的;实践出来的东西才是自己的,所以编程学习手不要太懒;
package wang.collection;
import java.util.ArrayList;
import java.util.Collection;
/**
* @version 1.0
* @auther WangCode
* @date 2021/2/27 22:22
*/
public class Test {
public static void main(String[] args) {
//创建Collection集合
Collection collection = new ArrayList<>();
//添加元素
collection.add("demo1");
collection.add("demo2");
collection.add(123456);
collection.add(true);
System.out.println(collection);
System.out.println("===========================================================");
//判断
System.out.println("collection.isEmpty() = " + collection.isEmpty());
System.out.println("collection.size() = " + collection.size());
System.out.println("collection.contains(123456) = " + collection.contains(123456));
System.out.println("===========================================================");
//删除
collection.remove(true);
System.out.println(collection);
System.out.println("===========================================================");
Collection collection1 = new ArrayList<>();
//把collection的所有元素添加到当前的集合
collection1.addAll(collection);
System.out.println("collection1 = " + collection1);
collection1.add("demo1");
System.out.println("collection1 = " + collection1);
//删除两个相同的元素会乍样
System.out.println("===========================================================");
collection1.remove("demo1");//删除匹配到的第一个元素,不会全部删除
System.out.println("collection1 = " + collection1);
//不会全部消失的;
System.out.println("===========================================================");
collection.removeAll(collection1);
System.out.println("collection = " + collection);
System.out.println("===========================================================");
//遍历集合中的元素
for (Object o : collection1) {
System.out.println(o);
System.out.println(o.getClass());//证明咱们存的是引用类型
}
}
}
"C:\Program Files\Java\jdk1.8.0_231\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.3.1\lib\idea_rt.jar=56592:C:\Program Files\JetBrains\IntelliJ IDEA 2020.3.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_231\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\rt.jar;F:\BaiduNetdiskDownload\源码笔记课件\代码\DataStructure\target\classes" wang.collection.Test
[demo1, demo2, 123456, true]
===========================================================
collection.isEmpty() = false
collection.size() = 4
collection.contains(123456) = true
===========================================================
[demo1, demo2, 123456]
===========================================================
collection1 = [demo1, demo2, 123456]
collection1 = [demo1, demo2, 123456, demo1]
===========================================================
collection1 = [demo2, 123456, demo1]
collection1 = [demo2, 123456, demo1, demo1]
===========================================================
collection = []
===========================================================
demo2
class java.lang.String
123456
class java.lang.Integer
demo1
class java.lang.String
demo1
class java.lang.String
Process finished with exit code 0
java8对集合也是有增强的,主要有removeIf stream
parallelStream spliterator
removeIf
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
作用是删除满足filter条件的元素。举一个简单的例子:
package wang.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Predicate;
/**
* @version 1.0
* @auther WangCode
* @date 2021/2/27 22:22
*/
public class Test {
public static void main(String[] args) {
//创建Collection集合
Collection<Integer> collection = new ArrayList<>();
//添加元素
collection.add(1);
collection.add(3);
collection.add(5);
collection.add(7);
System.out.println(collection);
//方法一:lambda表达式
collection.removeIf(item -> item>3);//删除大于3的元素
System.out.println(collection);
//方法二:Predicate函数
collection.removeIf(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer >= (Integer) 1;//删除大于等于1的元素
}
});
System.out.println(collection);
}
}
运行结果:
这个东西应该很实用。
stream
Stream是Java8新增的特性,对就是你们常说的流。但是他和I/O的关系不大,不要搞混了;咱们的这个流是对常见的集合数据处理的流。那咱们索性简称他为集合流吧,它可以执行非常复杂的查找过滤和映射数据等操作;
package wang.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* @version 1.0
* @auther WangCode
* @date 2021/2/27 22:22
*/
public class Test {
public static void main(String[] args) {
//创建Collection集合
Collection<Integer> collection = new ArrayList<>();
//添加元素
collection.add(1);
collection.add(3);
collection.add(5);
collection.add(7);
System.out.println(collection);
List<Integer> collect = collection.stream().filter(item -> item > 3).collect(Collectors.toList());
System.out.println(collection);
System.out.println(collect);
}
运行结果:
动不动咱们先来张图再说stream
咱们分析一下这段代码哈。😀
首先我们通过stream()获得了一个Stream对象;
调用Stream上的方法,filter()过滤出来了大于3的元素;
他的返回值仍然是一个Stream;
然后通过调用collect()方法并传递Collectors.toList()将结果集存放到一个List中;
当然Stream不止这些东西,但是篇幅有限,下次换个地方详解Stream;
parallelStream
使用多线程加快处理集合操作,底层原理使用了线程池ForkJoinPool;
Stream是串行流顺序输出,parallelStream乱序输出;
Stream线程安全,parallelStream存在多线程安全问题;
spliterator
Spliterator是一个可分割迭代器(splitable iterator)。Spliterator接口的出现是Java为了并行遍历数据源中的元素而设计的迭代器。另外我们还有一个迭代器Iterator,不过这个是顺序的。
小朋友,你是不是有很多问号?
为什么有Iterator还需要spliterator呐?
从最早Java提供顺序遍历迭代器Iterator时,那个时候还是单核时代,但现在多核时代下,顺序遍历已经不能满足需求了,如何把多个任务分配到不同核上并行执行,才是能最大发挥多核的能力,所以Spliterator应运而生啦。
四、Map接口
map的存值结构是KV键值对结构,Map集合的元素就是将K映射到V的对象;
并且还有几点注意的地方:
KV的数据结构可以是一样的或不一样也行;
K在一个集合里面不会出现重复的;
V在一个集合俩面是可以重复的;
每个K只能映射一个V,我国的一夫一妻制;
V put(K key, V value);
把指定的KV添加到Map集合中;
V remove(Object key);
把指定的键所对应的键值对元素在Map集合中删除返回被删除元素的值.
V get(Object key);
通过K获取V;
boolean containsKey(Object key);
判断是否包含指定的K;
boolean containsValue(Object value);
判断是否包含指定的V;
package wang.map;
import java.util.HashMap;
import java.util.Map;
/**
* @version 1.0
* @auther WangCode
* @date 2021/2/28 22:53
*/
public class Test {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("美国","英语");
map.put("中国","汉语");
for (Map.Entry<String,String> entry : map.entrySet()) {
System.out.println(entry.getKey()+"(K):"+entry.getValue()+"(V)");
}
}
}
Set<Map.Entry<K, V>> entrySet();返回的是K=V;
我们可以通过for循环使用Entry实现Map的遍历;
运行结果:
当然若只想看K或者是V我们大可不必上面的操作,还有性能更佳的方法,人呐,总是在不满足得到境况下进步的,咱们Java也是。
package wang.map;
import java.util.HashMap;
import java.util.Map;
/**
* @version 1.0
* @auther WangCode
* @date 2021/2/28 22:53
*/
public class Test {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("美国","英语");
map.put("中国","汉语");
System.out.println(map.keySet());
System.out.println(map.values());
}
}
运行结果:
package wang.map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @version 1.0
* @auther WangCode
* @date 2021/2/28 22:53
*/
public class Test {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("美国","英语");
map.put("中国","汉语");
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<String, String> next = iterator.next();
String key = next.getKey();
String value = next.getValue();
System.out.println(key+"(K):"+value+"(V)");
}
}
}
运行结果:
遍历map的方法,多种大家伺机而动,尽量找最优解。
接下来,会详细的讲解Set、List、Queue、Map的具体实现。尽情期待。