Java基础知识(8)
(包括:双列集合,不可变集合,Collections工具类,Stream流)
目录
Java基础知识(8)
一.双列集合
1. 双列集合的特点
2.Map
【1】Map的常见API
【2】Map的遍历
(1)Map集合的第一种遍历方式
(2) Map集合的第二种遍历方式
(3) Map集合的第三种遍历方式
3. HashMap
【1】HashMap的特点
【2】注意:
4. LinkedHashMap
【1】特点
5. TreeMap
【1】特点
【2】代码书写两种排序规则(类似TreeSet,去看基础(7))
6.可变参数
7. Collections
【1】Collections简介
【2】Collections常用的API
8. 不可变集合
【1】创建不可变集合的应用场景
【2】创建不可变集合的书写格式
二. Stream流
1.Stream流的作用
2.Stream流的使用步骤:
(1)获得Stream流
(2)Stream流的中间方法
(3)Stream流的终结方法
一.双列集合
1. 双列集合的特点
(1)双列集合一次需要存一对数据,分别为键和值
(2)键不能重复,值可以重复
(3)键和值是一一对应的,每一个键只能找到自己对应的值
(4)键+值这个整体 我们称之为“键值对”或者“键值对对象”,在Java中叫做“Entry对象”
2.Map
【1】Map的常见API
(1)Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的
(2)v put(K key,v value) 添加元素
//在添加数据的时候,如果键不存在,那么直接把键值对对象添加到map集合当中,方法返回nu11
//在添加数据的时候,如果键是存在的,那么会把原有的键值对对象覆盖,会把被覆盖的值进行返回。
(3)V remove(object key) 根据键删除键值对元素
(4)void clear() 移除所有的键值对元素
(5)boolean containsKey(Object key) 判断集合是否包含指定的键
(6)boolean containsValue(Object value) 判断集合是否包含指定的值
(7)boolean isEmpty() 判断集合是否为空
(8)int size() 集合的长度,也就是集合中键值对的个数
【2】Map的遍历
(1)Map集合的第一种遍历方式
//1.创建Map集合的对象
Map<String,string> map = new HashMap<>();
//2.添加元素
//3.通过键找值
//3.1获取所有的键,把这些键放到一个单列集合当中
set<string>keys = map.keyset();
//3.2遍历单列集合,得到每一个键
for(string key :keys){
System.out.println(key);
//3.3 利用map集合中的键获取对应的值get
String value = map.get(key);
System.out.println(key+"="+ value);
}
(2) Map集合的第二种遍历方式
//3.1 通过一个方法获取所有的键值对对象,返回一个set集合
Set<Map.Entry<String,string>>entries = map.entryset();
// 3.2 遍历entries这个集合,去得到里面的每一个键值对对象
for(Map.Entry<string,string>entry :entries){
//3.3 利用entry调用get方法获取键和值
String key = entry.getKey();
String value =entry.getValue();
System.out.println(key +"=”+ value);
}
(3) Map集合的第三种遍历方式
利用1ambda表达式进行遍历
map.forEach(new Biconsumer<String, string>(){
@override
public void accept(string key, string value){
System.out.println(key+"="+ value);
});
3. HashMap
【1】HashMap的特点
(1)HashMap是Map里面的一个实现类
(2)没有额外需要学习的特有方法,直接使用Map里面的方法就可以了
(3)特点都是由键决定的:无序、不重复、无索引
(4)HashMap跟Hashset底层原理是一模一样的,都是哈希表结构
【2】注意:
(1)依赖hashcode方法和equals方法保证键的唯一
(2)如果键存储的是自定义对象,需要重写hashcode和equals方法
如果值存储自定义对象,不需要重写hashcode和equals方法
4. LinkedHashMap
【1】特点
(1)由键决定:有序、不重复、无索引。
(2)这里的有序指的是保证存储和取出的元素顺序一致
(3)原理:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序
5. TreeMap
【1】特点
(1)TreeMap跟Treeset底层原理一样,都是红黑树结构的。
(2)由键决定特性:不重复、无索引、可排序
(3)可排序:对键进行排序.
(4)注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则
【2】代码书写两种排序规则(类似TreeSet,去看基础(7))
(1)实现Comparable接口,指定比较规则。
(2)创建集合时传递Comparator比较器对象,指定比较规则。
6.可变参数
(1)可变参数本质上就是一个数组
(2)作用:在形参中接收多个数据
(3)格式:数据类型..参数名称
举例:int...a
(4)注意事项
1)形参列表中可变参数只能有一个
2)可变参数必须放在形参列表的最后面
7. Collections
【1】Collections简介
(1)java.util.Collections:是集合工具类
(2)作用:Collections不是集合,而是集合的工具类。
【2】Collections常用的API
(1)public static<T>boolean addAll(Collection<T>c,T... elements) 批量添加元素
(2)public static void shuffle(List<?> list) 打乱List集合元素的顺序
(3)public static<T>void sort(List<T> list) 排序
(4)public static<T>void sort(List<T>list,Comparator<T>c) 根据指定的规则进行排序
(5)public static <T>int binarysearch(List<T>list,T key) 以二分查找法查找元素
(6)public static<T>void copy(List<T>dest, List<T> src) 拷贝集合中的元素
(7)public static<T>int fill(List<T>list, T obj) 使用指定的元素填充集合
(8)public static<T>void max/min(collection<T>coll) 根据默认的自然排序获取最大/小值
(9)public static<T>void swap(List<?>list,int i,int j) 交换集合中指定位置的元素
8. 不可变集合
【1】创建不可变集合的应用场景
(1)如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践.
(2)当集合对象被不可信的库调用时,不可变形式是安全的。
(3)简单理解:不想让别人修改集合中的内容
【2】创建不可变集合的书写格式
(1)在List、Set、Map接口中,都存在静态的of方法,可以获取一个不可变的集合。
(2)static <E> List<E> of(E...elements) 创建一个具有指定元素的List集合对象
(3)static <E> Set<E> of(E...elements) 创建一个具有指定元素的Set集合对象
(4)static<K,V> Map<K,V> of(E...elements) 创建一个具有指定元素的Map集合
(5)注意:
1)这个集合不能 添加,不能删除,不能修改。
2)当我们要获取一个不可变的set集合时,里面的参数一定要保证唯一性
3)创建Map的不可变集合时,键是不能重复的,Map里面的of方法,参数是有上限的,最多只能传递20个参数,10个键值对。
4)如果要建立大的Map,则可以:
①//获取到所有的键值对对象(Entry对象)
Set<Map.Entry<String,string>>entries = hm.entryset();
//把entries变成一个数组
Map.Entry[] arr1 = new Map.Entry[0];
//toArray方法在底层会比较集合的长度跟数组的长度两者的大小
//如果集合的长度 >数组的长度 : 数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
//如果集合的长度<=数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用
Map.Entry[] arr2 =entries.toArray(arr1);
//不可变的map集合
Map map = Map.ofEntries(arr2);
②Map<Object,Object>map = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));
③(在JDK10)Map<string,string>map=Map.copyOf(hm);
(6)如:List<String> list = List.of("张三","李叫","王五","赵六");
一旦创建完毕之后,是无法进行修改,只能进行查询操作
二. Stream流
1.Stream流的作用
结合了Lambda表达式,简化集合、数组的操作
2.Stream流的使用步骤:
① 先得到一条Stream流(流水线),并把数据放上去
② 利用Stream流中的API进行各种操作
过滤 转换 中间方法 方法调用完毕之后,还可以调用其他方法
统计 打印 终结方法 最后一步,调用完毕之后,不能调用其他方法
(1)获得Stream流
1)单列集合 default Stream<E>stream() Collection中的默认方法
如:ArrayList<string>list = new ArrayList<>();
list.stream().forEach(s->System.out.println(s));
2)双列集合 无 无法直接使用stream流
间接:HashMap<string,Integer>hm= new HashMap<>();
hm.keyset().stream().forEach(s->System.out.printin(s));(打印键)
或:hm.enterset().stream().forEach(s->System.out.printin(s));
3)数组 public static <T>Stream<T>stream(Tl array) Arrays工具类中的静态方法。
如:int[] arr ={1,2,3,4,5,6,7,8,9,10};
Arrays. Stream (arr).forEach(s->system.out.println(s));
4)一堆零散数据 public static<T> Stream<T> of(T... values) Stream接口中的静态方法。
如:Stream.of(1,2,3,4,5).forEach(s-> system.out.println(s));
注意stream接口中静态方法of的细节:
//方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
//但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到stream当中。
(2)Stream流的中间方法
1)Stream<T>filter(Predicate<? super T> predicate) 过滤
2)Stream<T>limit(long maxSize) 获取前几个元素
3)Stream<T> skip(long n) 跳过前几个元素
4)Stream<T> distinct() 元素去重,依赖(hashcode和equals方法)
5)static <T>Stream<T>concat(Stream a, Stream b) 合并a和b两个流为一个流
6)Stream<R> map(Function<T,R> mapper) 转换流中的数据类型
7)注意
/1/中间方法,返回新的stream流,原来的stream流只能使用一次,建议使用链式编程
/2/修改stream流中的数据,不会影响原来集合或者数组中的数据
如:①list.stream()
.filter(s ->s.startswith("张”))
.filter(s->s.length()== 3)
.forEach(s ->system.out.println(s));
②//list.stream().limit(3).forEach(s -> system.out.println(s));
③Stream.conca(list1.stream(),list2.stream()).forEach ( s-> System.out.printin(s));
④//string->int
//第一个类型:流中原本的数据类型
//第二个类型:要转成之后的类型
//apply的形参s:依次表示流里面的每一个数据
//返回值:表示转换之后的数据
//当map方法执行完毕之后,流上的数据就变成了整数
//所以在下面forEach当中,s依次表示流里面的每一个数据,这个数据现在就是整数了
list.stream().map(new Function<String, Integer>(){
@override
public Integer apply(String s){
string[]arr = s.split( regex:"-");
string agestring = arr[1];
int age = Integer.parseInt(agestring);
return age;
}).forEach(s->System.out.println(s));
(3)Stream流的终结方法
1)void forEach(Consumer action) 遍历
2)long count() 统计
3)toArray() 收集流中的数据,放到数组中
4)collect(Collector collector) 收集流中的数据,放到集合中
5)eg:
①// toArray():收集流中的数据,放到数组中
//IntFunction的泛型:具体类型的数组
//apply的形参:流中数据的个数,要跟数组的长度保持一致
//app1y的返回值:具体类型的数组
//方法体:就是创建数组
String[]arr =list.stream().toArray(new IntFunction<String[]>(){
@override
public string[]apply(int value){
return new string[value];
});
②Set<String>newlist2=list.stream().collect(collectors.toset());
③toMap :参数一表示键的生成规则
参数二表示值的生成规则
参数一:
Function泛型一:表示流中每一个数据的类型
泛型二:表示Map集合中键的数据类型
方法apply形参:依次表示流里面的每一个数据
方法体:生成键的代码
返回值:已经生成的键
参数二:
Function泛型一:表示流中每一个数据的类型
泛型二:表示Map集合中值的数据类型
方法apply形参:依次表示流里面的每一个数据
方法体:生成值的代码
返回值:已经生成的值
collect(Collectors.toMap(new Function<string,string>(){
@0verride
public string apply(string s){
return null;
}
},
new Function<String,Integer>(){
@override
public Integer apply(string s){
return null;
}));
注意点:如果我们要收集到Map集合当中,键不能重复,否则会报错