拓普网站建设,软装设计师资格证,前端开发和后端开发哪个赚钱,网站建设毕业设计任务书Java进阶08 集合#xff08;续#xff09;Stream流
一、HashSet集合类#xff08;续#xff09;
1、JDK7(-)HashSet原理解析
1.1 底层结构
数组链表
1.2 执行过程
①创建一个默认长度为16的数组#xff0c;数组名为table
②根据元素的哈希值跟数组的长度求余计…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(ListT list,T key)以二分查找法查找元素只能操作list集合public static T void copy(ListT dest,ListT src) 不常用拷贝集合中的元素public static T int fill(ListT list,T obj) 不常用使用指定的集合填充public static T void max/min(CollectionT coll)根据默认的自然排序获取最大/最小值public static T void swap(List? list,int i,int j)交换集合中指定位置的元素public static T void sort(ListT list)将集合中元素按默认规则排序public static T void sort(ListT list,Comparator? super T c)将集合中元素按照指定规则排序
注意两个排序方法只能对List集合排序使用默认规则排序方法对自定义类型的List集合排序时要让自定义类实现比较规则Comparable接口
2.2 方法使用Demo
public class CollectionsDemo {public static void main(String[] args) {// 1. 批量添加数据到集合ArrayListString list new ArrayList();Collections.addAll(list, a, b, c, d);System.out.println(list);
// 2. 打乱集合中的元素Collections.shuffle(list);System.out.println(list);
// 3. 使用二分查找法, 查找元素在集合的索引位置ArrayListInteger 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));
ArrayListStudent 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 ComparatorInteger() {Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});
System.out.println(nums);}
}
四、Map接口
1、Map介绍 三类Map集合TreeMap、HashMap、LinkedHashMap都实现了Map接口 Map集合都是双列集合每个元素包含两个数据 Map集合的每个元素的格式keyvalue键值对元素 key键不允许重复value值允许重复 键值对是一一对应的每个键只能找到自己对应的值 keyvalue这个整体称之为键值对或键值对对象在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)根据键查找对应的值SetK keySet()获取Map集合中所有的值
①调用keySet方法获取所有的键得到的是Set集合
②遍历Set集合获取每一个键
③遍历的过程中调用get方法根据键找值
public class HashMapDemo1 {public static void main(String[] args) {HashMapString,String map new HashMap();
map.put(张三,北京);map.put(李四,上海);map.put(王五,广州);
//1、获取所有的键SetString keySet map.keySet();//2、遍历Set集合获取每一个键for (String key : keySet) {//3、根据键查找对应的值String value map.get(key);System.out.println(key---value);}}
}
2、通过键值对对象获取键和值
方法说明SetMap.EntryK,V entrySet()获取集合中所有的键值对对象
Map.Entry类的方法
方法说明getKey()获取键getValue()获取值
①调用entrySet方法获取所有的键值对对象得到Set集合
②遍历Set集合获取每一个键值对对象
③通过键值对对象的getKey()和getValue()获取键和值
public class TreeMapDemo2 {/*键如果存储的是自定义类记得实现Comparable接口本Demo中的Student类要实现comparable接口*/public static void main(String[] args) {TreeMapStudent,String map new TreeMap();
map.put(new Student(张三,23),北京);map.put(new Student(李四,24),上海);map.put(new Student(王五,25),广州);
//1、调用entrySet方法获取所有的键值对对象SetMap.EntryStudent, String entrySet map.entrySet();//2、遍历entrySet集合获取每一个对象for (Map.EntryStudent, 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) {LinkedHashMapStudent,String map new LinkedHashMap();
map.put(new Student(张三,23),北京);map.put(new Student(李四,24),上海);map.put(new Student(王五,25),广州);
//匿名内部类foreachmap.forEach(new BiConsumerStudent, 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 StreamE stream()获取当前集合对象的Stream流
注意如果是双列集合Map只能间接获取。有以下三种方式 map.KeySet().Stream不推荐 map.values().Stream不推荐 map.EntrySet().Stream推荐 public class StreamDemo2 {public static void main(String[] args) {ListString list new ArrayListString();Collections.addAll(list,张三丰,张无忌,张翠山,王二麻子,张良,谢广坤);
SetString set new HashSetString();Collections.addAll(set,张三丰,张无忌,张翠山,王二麻子,张良,谢广坤);
MapString, Integer map new HashMapString, 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 StreamT 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 StreamT of(T...values)把一堆零散的数据封装到Stream流对象中
public class StreamDemo2 {StreamInteger s1 Stream.of(1, 2, 3, 4, 5, 6);s1.forEach(s- System.out.println(s));}
}
3、中间方法
方法说明StreamT filter(Predicate? super T predicate)用于对流中的数据进行过滤StreamT limit(long maxSize)获取前几个元素StreamT skip(long n)跳过前几个元素StreamT distinct()去除流中重复的元素依赖依赖hashCode和equals方法static T StreamT concat(Stream a,Stream b)合并a和b两个流为一个流
注意事项如果流对象已经被消费过就不允许再次使用了
public class StreamDemo4 {public static void main(String[] args) {ArrayListString list new ArrayListString();Collections.addAll(list,林青霞,张曼玉,王祖贤,柳岩,张敏,张无忌)// 需求1取前4个数据组成一个流StreamString s1 list.stream().limit(4);// 需求2跳过2个数据组成一个流StreamString 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) {ArrayListString list new ArrayList();Collections.addAll(list,zhangsan,23,lisi,24,wangwu,25);//根据需求创建Map来接姓名为键所以k为String类型年龄为值所以v为Integer类型 MapString,Integer map list.stream().filter(new PredicateString() {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 age24;}//调toMap往集合里装该方法有两个参数又分别是函数式接口写的时候要格外注意先写逗号}).collect(Collectors.toMap(new FunctionString, String() {Overridepublic String apply(String s) {//第一个参数位置存入k值即姓名return s.split(,)[0];}}, new FunctionString, Integer() {Overridepublic Integer apply(String s) {//第二个参数存入v值即年龄return Integer.parseInt(s.split(,)[1]);}}));
System.out.println(map);
}
}