Java进阶08 集合(续)Stream流

Java进阶08 集合(续)&Stream流

一、HashSet集合类(续)

1、JDK7(-)HashSet原理解析

1.1 底层结构

数组+链表

1.2 执行过程

①创建一个默认长度为16的数组,数组名为table

②根据元素的哈希值跟数组的长度求余计算出应存入的位置

③判断当前位置是否为null,如果是null直接头插法存入

④如果位置不为null,表示该位置已用元素,则调用equals方法比较

⑤如果元素内容一样,则不存;如果不一样,则头插法存入

2、⭐JDK8(+)HashSet原理解析

2.1 底层结构

哈希表(数组+链表+红黑树)

2.1 执行过程

①创建HashSet集合,默认长度为16、默认加载因子0.75的数组,数组名table

②调用集合的添加方法,添加对象调HashCode方法计算出应存入的索引位置(二次哈希值%数组长度)

③判断索引位置元素是否是null:是null,尾插法存入、不是null说明有元素,调用equals方法比较内容

④比较内容一样,不存;不一样,尾插法存入

2.3 提高查询性能
  • 扩容数组

    扩容条件

    • 当数组中的元素个数到达了16*0.75(加载因子)=12,扩容发生在第13次,扩容原数组2倍的大小

    • 链表挂载的元素超过了8(阈值),并且数组长度没有超过64

  • 链表转红黑树(极少触发)

    链表挂载的元素超过了(>)阈值8个,并且数组长度到达了(>=)64

3、相关面试题

Q:请说明HashSet实现的原理

A:首先,在添加元素时会先调用HashCode方法得到一个应存入位置的索引,然后检查该位置上是否有元素,没有直接尾插法存入,已有元素就需要调用equals方法逐个与该索引位置已存入的元素比较内容;内容均不相同则尾插法存入,相同就不存。其次,HashCode计算索引位置的过程是:首先调用HashCode方法得到原始的哈希值,再对该值进行哈希扰动右移16位,再和原始哈希值做异或操作得到二次哈希值,最后使用二次哈希值模与数组长度得到索引位置。但是在源码实现中,最后索引计算是通过数组长度减1再和二次哈希值逻辑与得到的,结果和上面一致,但与的执行效率比模更快。最后,之所以要对哈希值进行这么多复杂的操作是为了尽可能让要添加的元素哈希值散列在不同索引下,降低索引冲突。

二、LinkedHashSet集合类

LinkedList是Set集合中唯一可以去重并且存取有序的集合

1、存取有序原理

底层数据结构依然是哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序

♥单列集合使用场景大总结♥

List派系集合中,ArrayList集合首选;Set集合中,HashSet集合用的最多!

  • 集合元素可重复→→→选择ArrayList集合(用的最多)

  • 集合元素可重复,且增删操作多于查询→→→选择LinkedList

  • 对集合元素去重→→→选择HashSet集合(用的最多)

  • 对集合元素去重,且保证存取顺序→→→选择LinkedHashSet效率低于HashSet

  • 对集合元素进行排序→→→选择TreeSet,后续也可以用List集合实现排序

三、Collections集合类

1、可变参数

JDK5版本出现的技术,可以在定义方法的时候灵活的接收参数(可以不给参数,可以给1个或多个,也可以给一个数组),其底层本质就是一个数组。

  • 格式:数据类型...参数名称参考addAll方法的第二个参数

  • 注意事项:一个形参列表中可变参数只能有一个可变参数必须放在形参列表的最后面。

2、Collections集合工具类

java.utils.Collections是集合工具类,并不属于集合,只是用来操作集合的工具类

2.1 常用方法
方法说明
public static <T> boolean addAll(Collection<? super T> c,T...elements)批量添加数据到集合
public static void shuffle(List<?> list)打乱list集合元素的顺序(洗牌)
public static <T> int binarySearch(List<T> list,T key)二分查找法查找元素(只能操作list集合)
public static <T> void copy(List<T> dest,List<T> src) 不常用拷贝集合中的元素
public static <T> int fill(List<T> list,T obj) 不常用使用指定的集合填充
public static <T> void max/min(Collection<T> coll)根据默认的自然排序获取最大/最小值
public static <T> void swap(List<?> list,int i,int j)交换集合中指定位置的元素
public static <T> void sort(List<T> list)将集合中元素按默认规则排序
public static <T> void sort(List<T> list,Comparator<? super T> c)将集合中元素按照指定规则排序

注意:两个排序方法只能对List集合排序;使用默认规则排序方法对自定义类型的List集合排序时,要让自定义类实现比较规则Comparable接口

2.2 方法使用Demo
public class CollectionsDemo {public static void main(String[] args) {// 1. 批量添加数据到集合ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "a", "b", "c", "d");System.out.println(list);
​// 2. 打乱集合中的元素Collections.shuffle(list);System.out.println(list);
​// 3. 使用二分查找法, 查找元素在集合的索引位置ArrayList<Integer> nums = new ArrayList<>();Collections.addAll(nums, 1, 2, 3, 4, 5, 6, 7);System.out.println(Collections.binarySearch(nums, 3));
​// 4. 求最值 (这两个方法操作的数据, 需要具有可比性)System.out.println(Collections.max(nums));System.out.println(Collections.min(nums));
​ArrayList<Student> students = new ArrayList<>();Collections.addAll(students, new Student("张三", 23),new Student("李四", 24), new Student("王五", 25));
​System.out.println(Collections.max(students));System.out.println(Collections.min(students));
​// 5. 交换集合中指定索引位置的元素Collections.swap(nums, 0, 1);System.out.println(nums);
​// 6. 对集合内容排序 (自然排序)Collections.sort(list);System.out.println(list);
​// 7. 对集合内容排序 (比较器)Collections.sort(nums, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});
​System.out.println(nums);}
}

四、Map接口

1、Map介绍

  • 三类Map集合(TreeMap、HashMap、LinkedHashMap都实现了Map接口)

  • Map集合都是双列集合每个元素包含两个数据

  • Map集合的每个元素的格式:key=value(键值对元素)

    key(键)不允许重复;value(值)允许重复

    键值对是一一对应的,每个键只能找到自己对应的值

  • key+value这个整体,称之为键值对键值对对象,在Java中使用Entry对象表示

2、Map的常见API

Map是双列集合的顶层接口,它的功能是全部双列集合都可以继承使用的

方法说明
V put(K key,V value)添加元素
V remove(Object kesy)根据键删除键值对元素
void clear()移除所有的键值对元素
boolean containesKay(Object key)判断集合是否包含指定的键
boolean containsValue(Object value)判断集合是否包含指定的值
boolean isEmpty()判断集合是否为空
int size()集合的长度,也就是集合中键值对的个数

3、实现Map接口的集合

  • TreeMap:键(红黑树)键排序

  • HashMap:键(哈希表)键唯一

  • LinkedHashMap:键(哈希表+双向链表)键唯一,并保证存储顺序

双列集合的数据结构,都只针对于键有效,和值没有关系。HashMap的底层是哈希表结构的,依赖于hashCode方法和equals方法保证键值唯一因此,如果键存储的是自定义对象,需要重写hashCode和equals方法;如果值存储自定义对象,就不需要重写hashCode和equals方法

五、Map集合的遍历方式(3种)

1、 通过键找值

方法说明
V get(Object key)根据键查找对应的值
Set<K> keySet()获取Map集合中所有的值

①调用keySet方法获取所有的键(得到的是Set集合)

②遍历Set集合,获取每一个键

③遍历的过程中调用get方法,根据键找值

public class HashMapDemo1 {public static void main(String[] args) {HashMap<String,String> map = new HashMap<>();
​map.put("张三","北京");map.put("李四","上海");map.put("王五","广州");
​//1、获取所有的键Set<String> keySet = map.keySet();//2、遍历Set集合,获取每一个键for (String key : keySet) {//3、根据键查找对应的值String value = map.get(key);System.out.println(key+"---"+value);}}
}

2、通过键值对对象获取键和值

方法说明
Set<Map.Entry<K,V>> entrySet()获取集合中所有的键值对对象

Map.Entry类的方法

方法说明
getKey()获取键
getValue()获取值

①调用entrySet方法获取所有的键值对对象,得到Set集合

②遍历Set集合,获取每一个键值对对象

③通过键值对对象的getKey()和getValue()获取键和值

public class TreeMapDemo2 {/*键如果存储的是自定义类记得实现Comparable接口本Demo中的Student类要实现comparable接口*/public static void main(String[] args) {TreeMap<Student,String> map = new TreeMap<>();
​map.put(new Student("张三",23),"北京");map.put(new Student("李四",24),"上海");map.put(new Student("王五",25),"广州");
​//1、调用entrySet方法,获取所有的键值对对象Set<Map.Entry<Student, String>> entrySet = map.entrySet();//2、遍历entrySet集合获取每一个对象for (Map.Entry<Student, String> entry : entrySet) {//3、获取每一个entry对象的键和值System.out.println(entry.getKey()+entry.getValue());}}
}

3、通过foreach方法遍历

调用foreach方法直接遍历map拿到键和值

public class LinkedHashMapDemo3 {public static void main(String[] args) {LinkedHashMap<Student,String> map = new LinkedHashMap<>();
​map.put(new Student("张三",23),"北京");map.put(new Student("李四",24),"上海");map.put(new Student("王五",25),"广州");
​//匿名内部类foreachmap.forEach(new BiConsumer<Student, String>() {@Overridepublic void accept(Student key, String value) {System.out.println(key + "----" + value);}});
​//Lambda表达式foreachmap.forEach((key,value)->{System.out.println(key + "------" + value);});}
}

六、Stream流

1、Stream介绍

Stream流可以Lambda表达式,简化数组和集合操作

1.1 Stream流思想

可以将对数据的一系列操作理解为获取数据的Stream流对象将其放在Stream流水线上调用Stream的方法进行一些列处理操作。,因为Stream的方法处理完返回的对象也都是Stream对象,因此可以链式编程继续调用Stream的方法,直至最后有其他无返回值的方法终结操作。

2、获取Stream流对象

2.1 集合获取Stream流对象

使用Collection接口中的默认方法

方法名说明
default Stream<E> stream()获取当前集合对象的Stream流

注意:如果是双列集合Map,只能间接获取。有以下三种方式

  • map.KeySet().Stream不推荐

  • map.values().Stream不推荐

  • map.EntrySet().Stream推荐

    public class StreamDemo2 {public static void main(String[] args) {List<String> list = new ArrayList<String>();Collections.addAll(list,"张三丰","张无忌","张翠山","王二麻子","张良","谢广坤");
    ​Set<String> set = new HashSet<String>();Collections.addAll(set,"张三丰","张无忌","张翠山","王二麻子","张良","谢广坤");
    ​Map<String, Integer> map = new HashMap<String, Integer>();map.put("张三丰", 100);map.put("张无忌", 35);map.put("张翠山", 55);map.put("王二麻子", 22);map.put("张良", 30);map.put("谢广坤", 55);
    ​//list集合获取stream流对象遍历并打印list.stream().forEach(s-> System.out.println(s));//set集合获取stream流对象遍历并打印set.stream().forEach(s-> System.out.println(s));//map集合获取stream流对象遍历并打印map.entrySet().stream().forEach(s-> System.out.println(s));}
    }
     
2.2 数组获取Stream流对象

使用Arrays工具类中的静态方法Arrays.Stream(数组名)

方法名说明
static <T> Stream<T> stream(T[] array)将传入的数组封装到Stream流对象中
public class StreamDemo2 {public static void main(String[] args) {String[] names = {"张三","李四","王五"};//数组获取Stream流对象遍历并打印Arrays.stream(names).forEach(s-> System.out.println(s));
​int[] arr = {11,22,33};Arrays.stream(arr).forEach(s-> System.out.println(s));}
}
 
2.3 零散的数据获取Stream对象

使用Stream类中的静态方法

方法名说明
static <T> Stream<T> of(T...values)把一堆零散的数据封装到Stream流对象中
public class StreamDemo2 {Stream<Integer> s1 = Stream.of(1, 2, 3, 4, 5, 6);s1.forEach(s-> System.out.println(s));}
}

3、中间方法

方法说明
Stream<T> filter(Predicate<? super T> predicate)用于对流中的数据进行过滤
Stream<T> limit(long maxSize)获取前几个元素
Stream<T> skip(long n)跳过前几个元素
Stream<T> distinct()去除流中重复的元素依赖(依赖hashCode和equals方法)
static <T> Stream<T> concat(Stream a,Stream b)合并a和b两个流为一个流

注意事项:如果流对象已经被消费过,就不允许再次使用了

public class StreamDemo4 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<String>();Collections.addAll(list,"林青霞","张曼玉","王祖贤","柳岩","张敏","张无忌")// 需求1:取前4个数据组成一个流Stream<String> s1 = list.stream().limit(4);// 需求2:跳过2个数据组成一个流Stream<String> s2 = list.stream().skip(2);// 需求3:合并需求1和需求2得到的流,并把结果在控制台输出/*Stream.concat(s1,s2).forEach(s -> System.out.println(s));*/// 需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复//如果需求3的代码不注释掉,那需求4会报错。因为需求3已经消费过s1和s2这两个流了,需求4已不能再使用Stream.concat(s1,s2).distinct().forEach(s -> System.out.println(s));
​System.out.println(list.stream().count());}
}

4、终结操作方法

方法说明
void forEach(Consumer action)对此流的每个元素执行遍历操作
long count()返回此流中的元素数

5、Stream收集操作

  • Stream流操作,不会修改数据源

  • 把Stream流操作后的结果数据转回到集合

    方法说明
    R collect(Collector collector)开始收集Stream流,指定收集器
  • Collectors工具类提供了具体的收集方式

    方法说明
    public static <T> Collector tolist()把元素收集到list集合中
    public static <T> Collector toSet()把元素收集到Set集合中
    public static Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中
  • 收集toMap小Demo(格外注意)

    public class StreamDemo5 {/*需求:保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值*/public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();Collections.addAll(list,"zhangsan,23","lisi,24","wangwu,25");//根据需求创建Map来接,姓名为键所以k为String类型,年龄为值,所以v为Integer类型  Map<String,Integer> map = list.stream().filter(new Predicate<String>() {@Override//此处传入的参数s表示stream流拿到的list集合中的每一个数据,即每一个字符串public boolean test(String s) {//将拿到的每个字符串按逗号拆分为字符数组,下标0的元素为姓名,下标1的元素为年龄String[] arr = s.split(",");//由于接收到的年龄为String类型,需要转为int做范围逻辑判断int age = Integer.parseInt(arr[1]);//filter方法内部这个test方法接收布尔返回值,结果为true数据保留return age>=24;}//调toMap往集合里装,该方法有两个参数,又分别是函数式接口,写的时候要格外注意,先写逗号}).collect(Collectors.toMap(new Function<String, String>() {@Overridepublic String apply(String s) {//第一个参数位置存入k值,即姓名return s.split(",")[0];}}, new Function<String, Integer>() {@Overridepublic Integer apply(String s) {//第二个参数存入v值,即年龄return Integer.parseInt(s.split(",")[1]);}}));
    ​System.out.println(map);
    ​}
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/835464.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AcwingWeb应用课学习笔记

VSCode自动格式化 选中Format On Save不起作用 在设置中搜索default formatter&#xff0c;修改成Prettier-Code formatter meta标签 HTML 元素表示那些不能由其它 HTML 元相关&#xff08;meta-related&#xff09;元素&#xff08;(、,

网络补充笔记

目录 OSI 开放式系统互联参考模型 --- 7层参考模型 UDP&#xff1a;用户数据报文协议 --- 非面向不可靠的传输协议&#xff1b;传输层基本协议&#xff0c;仅完成传输层的基本工作 --- 分段、端口号 TCP&#xff1a;传输控制协议 --- 面向连接的可靠性传输协议 出了完成传输层…

揭秘APP广告变现:自建平台收益倍增秘诀

在数字广告领域&#xff0c;应用&#xff08;APP&#xff09;广告变现项目是实现收益的重要途径。随着移动互联网的蓬勃发展&#xff0c;自建平台进行广告投放和收益优化成为了众多开发者和企业关注的焦点。为了确保最大化收益&#xff0c;我们不仅需要对广告市场有深刻的了解&…

高性能运营级流媒体服务框架:支持多协议互转 | 开源日报 No.250

ZLMediaKit/ZLMediaKit Stars: 12.6k License: NOASSERTION ZLMediaKit 是一个基于 C11 的高性能运营级流媒体服务框架。 使用 C11 开发&#xff0c;避免裸指针&#xff0c;代码稳定可靠&#xff0c;性能优越。支持多种协议 (RTSP/RTMP/HLS/HTTP-FLV/WebSocket-FLV/GB28181 等…

武汉星起航助力新手卖家掌握亚马逊政策,开启跨境电商新征程

在数字化浪潮席卷全球的今天&#xff0c;亚马逊平台以其强大的影响力和广阔的市场前景&#xff0c;吸引了越来越多的卖家涌入其中。然而&#xff0c;对于初涉亚马逊市场的新手卖家而言&#xff0c;如何在激烈的市场竞争中立足&#xff0c;并成功开展跨境电商业务&#xff0c;却…

LaTeX公式学习笔记

\sqrt[3]{100} \frac{2}{3} \sum_{i0}^{n} x^{3} \log_{a}{b} \vec{a} \bar{a} \lim_{x \to \infty} \Delta A B C \alpha αΑ\xiξ\XiΞ\beta βΒ\pi π\PiΠ\gamma γ\GammaΓ\varpiϖ\delta δ\DeltaΔ\rhoρΡ\epsilon ϵΕ\varrho ϱ\varepsilo…

MySql数据库基础知识

大家好&#xff0c;在当今软件世界中&#xff0c;软件测试人员肩负着至关重要的职责&#xff0c;确保软件的质量与稳定性。而对于软件测试工作来说&#xff0c;了解 MySQL 基础知识是一项极具价值的技能。MySQL 作为广泛应用的关系型数据库管理系统&#xff0c;在众多软件项目中…

万村乐数字乡村综合服务系统如何助力农民收入的腾飞

作为行业领先的数字乡村综合服务系统——“万村乐”&#xff0c;其核心便是基于互联网乡村和物联网乡村的强大信息基石之上。通过幸福民生服务、高效政务服务以及规范的党务服务这三条主线&#xff0c;以手机端平台为承载&#xff0c;借助事件反馈、精准种养数据、精细人员网格…

UEC++ FString做为参数取值时报错error:C4840

问题描述 用来取FString类型的变量时报错&#xff1a; 问题解决 点击错误位置&#xff0c;跳转到代码&#xff1a; void AMyDelegateActor::TwoParamDelegateFunc(int32 param1, FString param2) {UE_LOG(LogTemp, Warning, TEXT("Two Param1:%d Param2:%s"), param…

【全开源】酷柚易汛ERP 源码部署/售后更新/上线维护

一款基于FastAdminThinkPHPLayui开发的ERP管理系统&#xff0c;帮助中小企业实现ERP管理规范化&#xff0c;此系统能为你解决五大方面的经营问题&#xff1a;1.采购管理 2.销售管理 3.仓库管理 4.资金管理 5.生产管理&#xff0c;适用于&#xff1a;服装鞋帽、化妆品、机械机电…

数字型隔离器ISO121x的用法

目录 概述 1 认识ISO121x 1.1 简介 1.2 特性 1.3 应用领域 2 ISO121x芯片结构 2.1 ISO1211引脚介绍 2.2 ISO1211的通用应用电路 2.3 Layout Example 3 应用范例 3.1 TI提供的评估板 3.2 评估板的原理图电路 概述 本文主要介绍ISO121x的相关特性&#xff0c;以及其…

导出QQ好友列表、群列表、群员列表

MENU 准备工作在浏览器地址栏中输入地址使用F12快捷键打开开发者工具(浏览器控制台)点击头像登入网站(推荐)或手机扫码登录获取群列表获取好友列表获取群员列表 准备工作 一台带有浏览器的电脑 在浏览器地址栏中输入地址 https://qun.qq.com/member.html 使用F12快捷键打开开发…

洪水仿真模拟(ArcGIS),水利数字孪生新利器

这两天ArcGIS Pro的官方账号释放了一个名为“Flood Simulation in ArcGIS Pro”的洪水模拟功能视频。根据视频详情页的介绍&#xff0c;该洪水仿真模拟功能会作为新功能出现在ArcGIS Pro 3.3中。 由于我目前从事的主要应用方向都是弱GIS的领域&#xff0c;所以我已经很久没有再…

Panasonic机器人维修|松下机械手维修过程

在我们的科技日新月异的今天&#xff0c;松下机器人已经广泛应用于各个领域&#xff0c;发挥着越来越重要的作用。然而&#xff0c;这些Panasonic机械手维修过程也是一项重要且复杂的工作。 一、准备工作 在进行松下机器人维修前&#xff0c;需要充分了解机器人的构造和工作原理…

头歌实践教学平台:CG1-v1.0-点和直线的绘制

第1关&#xff1a;OpenGL点的绘制 一. 任务描述 根据下面要求&#xff0c;在右侧修改代码&#xff0c;绘制出预期输出的图片。平台会对你编写的代码进行测试。 1.本关任务 熟悉编程环境&#xff1b; 了解光栅图形显示器的特点&#xff1b; 了解计算机绘图的特点&#xff1b…

自动化运维管理工具----------Ansible模块详细解读

目录 一、自动化运维工具有哪些&#xff1f; 1.1Chef 1.2puppet 1.3Saltstack 二、Ansible介绍 2.1Ansible简介 2.2Ansible特点 2.3Ansible工作原理及流程 2.3.1内部流程 2.3.2外部流程 三、Ansible部署 3.1环境准备 3.2管理端安装 ansible 3.3Ansible相关文件 …

图片转pdf的java代码实现

一、实现方式 采用itextpdf和itext包&#xff0c;使用java代码&#xff0c;把图片转换为pdf. 支持文件格式&#xff1a;png&#xff0c;jpg, jpeg,gif 二、java代码实现 1、maven依赖 <!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf --><dependen…

反了!美国假冒邮政服务钓鱼网站访问量竟然超过正规官网

美国邮政是美国主要的包裹信件投递机构之一&#xff0c;长期以来该单位都是网络钓鱼和诈骗的针对目标。对美国公民来说&#xff0c;在假期通常都会收到声称来自美国邮政的诈骗。美国邮政甚至单独建设的网页提醒消费者警惕诈骗信息&#xff1a; 专用提醒网页 Akamai 的研究人员…

Redis是单线程吗?为什么6.0之后引入了多线程?

Redis是单线程吗&#xff1f;为什么6.0之后引入了多线程&#xff1f; Redis 是单线程吗&#xff1f;Redis 单线程模式是怎样的&#xff1f;Redis 采用单线程为什么还这么快&#xff1f;Redis 6.0 之前为什么使用单线程&#xff1f;Redis 6.0 之后为什么引入了多线程&#xff1f…

在拥有多个同名称密码的ap环境中,如何连接到指定信道或mac的ap路由器?

在给客户做ESP32-C3入墙开关项目时&#xff0c;客户问&#xff1a;在拥有多个同名称密码的ap环境中&#xff0c;如何连接到指定信道或mac的ap路由器&#xff1f;针对这个问题&#xff0c;启明云端工程师给出下面解决方法。 1、将wifi_sta_config_t配置中的channel配置为该信道…