day17
可变参数
- 就是说一种特殊形参,定义在方法、构造器的形参列表里,格式是:数据类型...参数名称
可变参数的1特点与好处
-
特点:可以不传数据给它,可以传一个或者同时多个数据给它;也可以传一个数组给它
-
好处:常常用来灵活的接受数据
可变参数的本质就是一个数组
可变参数的注意事项
- 可变参数在方法内部就是一个数组
- 可变参数必须放在形参列表的最后面
- 一个形参列表的可变参数只能有一个
可变参数的应用场景
- 可以很方便的创建集合对象
Collections是一个集合工具类,方便操作集合
方法名称 | 说明 |
---|---|
public static |
给集合批量添加元素 |
public static void shuffle(List<?> list) | 打乱List集合中的元素顺序 |
public static |
对List集合中的元素进行升序排序 |
public static |
对List集合中元素,按照比较器对象指定的规则进行排序 |
Map集合
- Map集合称为双列集合,格式:{key1 = value1,key2 = value2,...}一次需要存一对数据作为一个元素
- Map集合的每个元素“Key=value”称为一个键值对/键值对对象/一个Entry对象,Map集合也被叫做键值对集合
- Map集合的所有键是不允许重复的,但是值可以重复,键和值是一一对应的,每一个键只能找到自己对应的值
调用put方法时,如果添加重复的Key,会覆盖Key的value值
Map集合体系的特点
注意:Map系列集合的特点都是由键决定的,值只是一个附属品,值是不作要求的
- HashMap(由键决定特点):无序、不重复、无索引;(用的最多)
- LinkedHashMap(由键决定特点):有序、不重复、无索引
- TreeMap(由键决定特点):无序、不重复、无索引
Map集合常用方法
- Map集合是双列集合的祖宗,他的功能是全部双列集合都可以继承过来使用的
方法名称 | 说明 |
---|---|
public V put(K key,V value) | 添加元素 |
public int size() | 获取集合的大小 |
public void clear() | 清空集合 |
public boolean isEmpty() | 判断集合是否为空,为空返回true , 反之 |
public V get(Object key) | 根据键获取对应值 |
public V remove(Object key) | 根据键删除整个元素 |
public boolean containsKey(Object key) | 判断是否包含某个键 |
public boolean containsValue(Object value) | 判断是否包含某个值 |
public Set |
获取全部键的集合 |
public Collection |
获取Map集合的全部值 |
遍历Map集合的三种方式
-
获取所有Key的集合然后遍历,通过Key值获取对应的value值
方法名称 说明 public Set keySet() 获取所有键的集合 public V get(Object key) 根据键获取其对应的值 -
把键值对看成一个整体进行遍历(难度较大)
Map提供的方法 说明 Set<Map.Entry<K, V>> entrySet() 获取所有“键值对”的集合 Map.Entry提供的方法 说明 K getKey() 获取键 V getValue() 获取值 -
Lambda表达式
方法名称 | 说明 |
---|---|
default void forEach(BiConsumer<? super K, ? super V> action) | 结合lambda遍历Map集合 |
public class forDemo {
public static void main(String[] args) {
HashMap<String, Integer> maps = new HashMap<>();
String[] arr = {"A","B","C","D"};
for (int i = 0;i < 80;i++){
Random random = new Random();
String s = arr[random.nextInt(arr.length)];
int v = maps.getOrDefault(s,0);//HashMap 的 getOrDefault(Object key, V defaultValue) 方法用于获取指定键对应的值,如果键不存在,则返回默认值。
maps.put(s,v+1);
}
//循环遍历 keySet
Set<String> keySet = maps.keySet();
for (String key : keySet) {
Integer value = maps.get(key);
System.out.println(key +"--"+value);
}
System.out.println("----------------------------");
//entrySet
Set<Map.Entry<String,Integer>> entries = maps.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
System.out.println(entry.getKey()+"---"+entry.getValue());
}
System.out.println("----------------------------");
//forEach
maps.forEach(new BiConsumer<String, Integer>() {
@Override
public void accept(String s, Integer integer) {
System.out.println(s+"----"+integer);
}
});
//forEach+lambda
maps.forEach((key,value)-> System.out.println(key +"-"+value));
}
}
HashMap
底层原理
哈希表
HashMap的底层实现是一个数组和链表(或红黑树)的结合体,它通过哈希函数将键映射到数组中的一个位置上,并将对应的值存储在这个位置上。
HashMap的底层原理如下:
-
初始化:HashMap创建时会创建一个默认大小的数组,这个数组大小是16,同时会计算出一个装载因子0.75,表示当数组中的元素数量达到总容量的75%时,就需要扩容。
-
插入:当用户调用put()方法插入键值对时,首先会根据键的哈希值计算出它在数组中的索引位置。如果这个位置还没有元素,则将这个键值对直接存储在这个位置上;如果这个位置已经存在元素,就需要遍历这个位置上的链表(或红黑树),找到对应的键值对,并更新它的值。
-
扩容:当HashMap中元素的数量达到总容量的75%时,就会自动进行扩容。具体来说,它会创建一个新的数组,大小是原来的两倍,并将所有元素重新插入到新的数组中。
-
查询:当用户调用get()方法查询某个键对应的值时,HashMap会根据键的哈希值计算出它在数组中的索引位置,并在该位置上的链表(或红黑树)中查找对应的键值对。
-
删除:当用户调用remove()方法删除某个键值对时,HashMap会根据键的哈希值计算出它在数组中的索引位置,并在该位置上的链表(或红黑树)中查找对应的键值对,并将它从链表(或红黑树)中删除。
HashMap特点
HashMap集合是一种增删改查数据,性能都比较好的集合
他是无序,不能重复,没有索引支持的(由键决定特点)
HashMap的键依赖HashCode方法和equals方法保证键的唯一
如果键存储的是自定义类型的对象,可以通过重写HashCode和equals,这样可以保证多个对象内容一样时,HashMap集合就能认去重了
LinkedHashMap
- 有序 不重复 无索引
底层原理
LinkedHashMap是HashMap的一个子类,它的底层实现方式基本上和HashMap相同,只不过在HashMap的基础上增加了一个双向链表来维护插入顺序或访问顺序,因此它既可以保持键值对的插入顺序,也可以按照访问顺序进行遍历。
TreeMap
- 无序、不可重复、无索引、但可按照指定规则排序
TreeMap是Java集合框架中的一种实现,它是一种基于红黑树的有序映射表。在TreeMap中,每个键值对都存储在一个节点中,节点按照键的大小顺序排列组成一颗红黑树,这样就可以快速地查找、插入和删除节点。
TreeMap底层原理
下面是TreeMap底层的具体实现原理:
- 数据结构:TreeMap底层使用红黑树作为存储数据的数据结构。红黑树是一种自平衡的二叉查找树,它可以保证在最坏情况下,查找、插入和删除操作的时间复杂度都为O(logn)。
- 排序:TreeMap中的节点按照键的大小顺序排列。如果两个键的比较结果相同,那么它们被视为相等,只能存储一个键值对。TreeMap提供了两种比较方式:使用键的自然顺序(Natural Ordering)或者使用一个Comparator进行比较。
- 插入:在TreeMap中插入节点时,会根据键的大小顺序找到要插入的位置。如果要插入的键已经存在,那么它的值会被更新。插入节点后,需要保持红黑树的平衡性质。
- 删除:在TreeMap中删除节点时,会根据键的大小顺序找到要删除的节点。如果要删除的节点有两个子节点,那么需要找到它的后继节点(即大于该节点的最小节点)来替换它。删除节点后,需要保持红黑树的平衡性质。
- 遍历:TreeMap支持三种遍历方式:按键的自然顺序升序遍历、按键的自然顺序降序遍历、按照指定的Comparator进行遍历。这些遍历方式都是基于红黑树的中序遍历实现的。
Stream
简化集合、数组操作的API.结合了Lambda表达式
-
也叫Stream流,JDK8开始新增的一套API,可以用于操作集合或者数组的数据。
-
优势:Stream流大量结合了Lambda的语法风格来编程,提供了一种更加强大,更加简单的方式操作集合或者数组中的数据,代码更简洁,可读性更好
Stream 的操作可以分为两类:中间操作和终止操作。中间操作可以返回一个新的 Stream 对象,终止操作则可以将 Stream 转换为另外一种数据类型(如 List、Set、Map、数组等),或对集合进行统计、归约等操作。
Stream操作步骤
2.获取Stream流
获取集合的Stream流
Collection提供的如下方法 | 说明 |
---|---|
default Stream |
获取当前集合对象的Stream流 |
获取数组的Stream流
Arrays类提供的如下 方法 | 说明 |
---|---|
public static |
获取当前数组的Stream流 |
Stream类提供的如下 方法 | 说明 |
---|---|
public static |
获取当前接收数据的Stream流 |
2.Stream流的中间方法
- 中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程)。
-
filter(Predicate<T> predicate)
:过滤出符合条件的元素。 -
map(Function<T, R> mapper)
:将元素进行映射,返回一个新的 Stream。 -
flatMap(Function<T, Stream<R>> mapper)
:将元素进行映射,并将所有 Stream 中的元素合并为一个 Stream。 -
sorted(Comparator<T> comparator)
:对元素进行排序。 -
distinct()
:去除重复的元素。 -
limit(long maxSize)
:截取前 maxSize 个元素。 -
skip(long n)
:跳过前 n 个元素。 -
reduce(T identity, BinaryOperator<T> accumulator)
:将元素聚合为一个值。 -
collect(Collector<T, A, R> collector)
:将元素收集到一个容器中。 -
forEach(Consumer<T> action)
:对每个元素执行操作。 -
Stream提供的常用中间方法 说明 Stream filter(Predicate<? super T> predicate) 用于对流中的数据进行过滤。 Stream sorted() 对元素进行升序排序 Stream sorted(Comparator<? super T> comparator) 按照指定规则排序 Stream limit(long maxSize) 获取前几个元素 Stream skip(long n) 跳过前几个元素 Stream distinct() 去除流中重复的元素。 Stream map(Function<? super T,? extends R> mapper) 对元素进行加工,并返回对应的新流 static Stream concat(Stream a, Stream b) 合并a和b两个流为一个流
3.Stream流常见的终结方法
- 收集Stream流:就是把Stream流操作后的结果转回到集合或者数组中去返回
- Stream流:方便操作集合/数组的手段;
- 集合/数组:才是开发中的目的
Stream提供的常用终结方法 | 说明 |
---|---|
void forEach(Consumer action) | 对此流运算后的元素执行遍历 |
long count() | 统计此流运算后的元素个数 |
Optional |
获取此流运算后的最大值元素 |
Optional |
获取此流运算后的最小值元素 |
Stream的注意事项
- Stream流中无法直接修改集合,数组等数据源中的数据
- 同一个Stream对象只能调用一次方法