怎么做网站上的模拟动画,建站网站系统,做阿里网站卖东西赚钱,网站建设云服务器与虚拟主机文章目录 JDK8新特性#xff1a;Lambda表达式认识Lambda表达式Lambda表达式的省略规则 JDK8新特性#xff1a;方法引用静态方法的引用实例方法的引用特定类型方法的引用构造器的应用 集合➡️Collection单列集合体系Collection的常用方法Collection的遍历方法迭代器增强for循… 文章目录 JDK8新特性Lambda表达式认识Lambda表达式Lambda表达式的省略规则 JDK8新特性方法引用静态方法的引用实例方法的引用特定类型方法的引用构造器的应用 集合➡️Collection单列集合体系Collection的常用方法Collection的遍历方法迭代器增强for循环lambda表达式案例 List集合List特点、特有方法List的遍历方式ArrayList集合的底层原理ArrayList集合的底层原理ArrayList集合适合的应用场景 LinkedList集合的底层原理LinkedList集合的底层原理**LinkedList**新增特有方法**LinkedList**集合适合的应用场景场景一可以用来设计队列场景二可以用来设计栈 Set集合Set集合的特点HashSet集合的底层逻辑前导知识哈希值对象哈希值的特点哈希表数据结构树 HashSet集合底层原理HashSet集合去重复的机制 LinkedHashSet集合的底层逻辑TreeSet集合 ✅总结场景选择注意事项集合的并发修改异常问题Collection的其他相关知识可变参数Collections工具类综合案例 ➡️Map集合概述常用方法遍历方法方法1键找值方法2键值对方法3Lambda 案例 Map集合-统计投票人数HashMapHashMap底层原理 LinkedHashMapLinkedHashMap底层原理 TreeMap补充知识集合的嵌套 Stream流认识StreamStream流的使用步骤 Stream的常用方法1、获取Stream流2、Stream流常见的中间方法3、Stream流常见的终结方法 JDK8新特性Lambda表达式
认识Lambda表达式 Lambda表达式是DK8开始新增的一种语法形式作用用于简化匿名内部类的代码写法。 格式 注意Lambda表达式并不能简化全部匿名内部类的写法只能简化函数式接口有且只有一个抽象方法的接口的匿名内部类。
package lambda;public class LambdaTest1 {public static void main(String[] args) {Swimming s new Swimming() {Overridepublic void swim() {System.out.println(学生游泳);}};s.swim();}
}interface Swimming{void swim();
}简化后
package lambda;public class LambdaTest1 {public static void main(String[] args) {
// Swimming s new Swimming() {
// Override
// public void swim() {
// System.out.println(学生游泳);
// }
// };
// s.swim();//简化后Swimming s () - {System.out.println(学生游泳);};s.swim();}
}interface Swimming{void swim();
}将来我们见到的大部分函数式接口上面都可能会有一个FunctionalInterface的注解有该注解的接口就必定是函数式接口。 Lambda表达式的省略规则
Lambda表达式的省略写法进一步简化Lambda表达式的写法
参数类型可以省略不写。如果只有一个参数参数类型可以省略同时()也可以省略。如果Lambda表达式中的方法体代码只有一行代码可以省略大括号不写同时要省略分号此时如果这行代码是return语句也必须去掉return不写。
Arrays.setAll(prices, (int value) -{return prices[value] * 0.8;
});//可以简化为
Arrays.setAll(prices, (value) -{return prices[value] * 0.8;
});//接着简化
Arrays.setAll(prices, value -{return prices[value] * 0.8;
});//接着简化
Arrays.setAll(prices, value - prices[value] * 0.8);再或者
Arrays.sort(students, new ComparatorStudent() {Overridepublic int compare(Student o1, Student o2){return Double.compare(o1.getHeight)}
});//可以简化为
Arrays.sort(students, (Student o1, Student o2) - {return Double.compare(o1.getHeight(), o2.getHeight()); //升序
});//接着简化
Arrays.sort(students, (o1, o2) - {return Double.compare(o1.getHeight(), o2.getHeight()); //升序
});//接着简化
Arrays.sort(students, (o1, o2) - Double.compare(o1.getHeight(), o2.getHeight()) );用来简化函数式接口的匿名内部类
JDK8新特性方法引用
用于进一步简化Lambda表达式的
方法引用的标志性符号 “ :: ”
静态方法的引用
类名 :: 静态方法使用场景如果某个Lambda表达式里只是调用一个静态方法并且前后参数的形式一致就可以使用静态方法引用 实例方法的引用 对象名 :: 实例方法 使用场景如果某个Lambda表达式里只是调用一个实例方法并且前后参数的形式一致就可以使用实例方法引用 特定类型方法的引用 类型 :: 方法 使用场景如果某个Lambda表达式里只是调用一个实例方法并且前面参数列表中的第一个参数是作为方法的主调后面的所有参数都是作为该实例方法入参的则此时就可以使用特定类型的方法引用。 构造器的应用
类名 :: new使用场景如果某个Lambda表达式里只是在创建对象并且前后参数的情况一致就可以使用构造器引用 集合
集合是一种容器用来装数据的类似于数组但集合的大小可变开发中也非常常用
集合的体系结构 集合分为Collection单列集合Map双列集合
➡️Collection单列集合体系 Collection集合特点
List系列集合添加的元素是有序取时的顺序和拿时的顺序是一致的、可重复可以往集合中加一模一样的数据、有索引。 ArrayList有序、可重复、有索引LinkedList有序、可重复、有索引 Set系列集合添加的元素是无序、不重复、无索引。 HashSet无序、不重复、无索引LinkedHashSet有序、不重复、无索引TreeSet按照大小默认升序排序、不重复、无索引
package collection;import java.util.ArrayList;
import java.util.HashSet;public class CollectionTest1 {public static void main(String[] args) {ArrayListString list new ArrayList(); //List有序 可重复 有索引list.add(java1);list.add(java2);list.add(java3);list.add(java4);list.add(java5);System.out.println(list);HashSetString set new HashSet(); //Set 无序 无重复 无索引set.add(java1);set.add(java2);set.add(java3);set.add(java2);set.add(java1);System.out.println(set);}
}//Out:
[java1, java2, java3, java4, java5]
[java3, java2, java1]集合的存储对象存的并不是元素本身而是元素的地址通过元素地址到栈里面获取元素
Collection的常用方法
Collection是单列集合的祖宗它规定的方法功能是全部单列集合都会继承的。
Collection的常见方法单列集合都能用 package collection;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;public class CollectionTest2API {public static void main(String[] args) {CollectionString c new ArrayList();//1.public boolean add(E e)添加元素,添加成功返回true。c.add(java1);c.add(java1);c.add(java2);c.add(java2);c.add(java3);System.out.println(c);//2.public void clear()清空集合的元素。
// c.clear();
// System.out.println(c);//3.public boolean isEmpty()判断集合是否为空是空返回true反之。System.out.println(c.isEmpty());//4.public int size()获取集合的大小。System.out.println(c.size());//5.public boolean contains(object obj)判断集合中是否包含某个元素。System.out.println(c.contains(java3));System.out.println(c.contains(Java3)); //精确匹配所以是false//6.public boolean remove(E e)删除某个元素如果有多个重复元素默认删除前面的第一个System.out.println(c.remove(java1)); //trueSystem.out.println(c);//7.public Object[] toArray()把集合转换成数组Object[] arr c.toArray();System.out.println(Arrays.toString(arr));String[] arr2 c.toArray(new String[c.size()]); //指定一个String类型的数组System.out.println(Arrays.toString(arr2));System.out.println();//把一个集合里的全部数据倒入到另一个集合中去CollectionString c1 new ArrayList();c1.add(java1);c1.add(java2);CollectionString c2 new ArrayList();c2.add(java3);c2.add(java4);c1.addAll(c2); //就是把c2集合的全部数据倒入到c1集合中去System.out.println(c1);System.out.println(c2); //不空相当于拷贝}
}
//Out:
[java1, java1, java2, java2, java3]
false
5
true
false
true
[java1, java2, java2, java3]
[java1, java2, java2, java3]
[java1, java2, java2, java3][java1, java2, java3, java4]
[java3, java4]Collection的遍历方法
迭代器 迭代器是用来遍历集合的专用方式(数组没有选代器)在java中选代器的代表是Iterator。 Collection集合获取迭代器的方法 Iterator迭代器中的常用方法 package collection;import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;public class CollectionDemo1 {public static void main(String[] args) {CollectionString c new ArrayList();c.add(aaa);c.add(sss);c.add(ddd);c.add(fff);System.out.println(c);// c [aaa,sss,ddd,fff]// it it的位置it会把数据取出来然后往后移动一位//使用迭代器遍历集合//1、从集合对象中获取迭代器对象IteratorString it c.iterator();
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next());
// System.out.println(it.next());// System.out.println(it.next()); //出现异常NoSuchElementException//2、我们应该使用循环结合迭代器遍历集合while (it.hasNext()){String ele it.next();System.out.println(ele);}}
}
//Out:
[aaa, sss, ddd, fff]
aaa
sss
ddd
fff增强for循环 增强for可以用来遍历集合或者数组。增强for遍历集合本质就是迭代器遍历集合的简化写法。
package collection;import java.util.ArrayList;
import java.util.Collection;public class CollectionDemo2 {public static void main(String[] args) {CollectionString c new ArrayList();c.add(aaa);c.add(sss);c.add(ddd);c.add(fff);System.out.println(c);// c [aaa,sss,ddd,fff]// ele ele类似游标//使用增强for遍历集合或者数组//快捷键c.for 然后回车改变量名就行for (String ele : c){System.out.println(ele);}String[] names {11,22,33};for (String name : names){System.out.println(name);}}
}//Out:
[aaa, sss, ddd, fff]
aaa
sss
ddd
fff
11
22
33lambda表达式
Lambda表达式遍历集合:
得益于JDK8开始的新技术Lambda表达式提供了一种更简单、更直接的方式来遍历集合。
需要使用Collection的如下方法来完成 package collection;import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;public class CollectionDemo3 {public static void main(String[] args) {CollectionString c new ArrayList();c.add(aaa);c.add(sss);c.add(ddd);c.add(fff);System.out.println(c);// c [aaa,sss,ddd,fff]// sc.forEach(new ConsumerString() {Overridepublic void accept(String s) {System.out.println(s);}});}
}
//Out:
[aaa, sss, ddd, fff]
aaa
sss
ddd
fff可以用Lambda进行简化
c.forEach((String s) - {System.out.println(s);});
//再简化
c.forEach(s - {System.out.println(s);});
//再简化
c.forEach(s - System.out.println(s));
//再简化
c.forEach(System.out::println);案例 集合的存储对象存的并不是元素本身而是元素的地址通过元素地址到栈里面获取元素
List集合
有啥特点是否有特有功能适合什么业务场景
List系列集合有序、可重复、有索引。两个底层实现不同适合的场景不同
ArrayList有序、可重复、有索引LinkedList有序、可重复、有索引
List特点、特有方法
List集合特有的方法
List集合因为支持索引所以多了很多与索引相关的方法。同时Collection的功能List也都继承了。 List list new ArrayList(); //一行经典代码设计到多态优雅用的多 package list;import java.util.ArrayList;
import java.util.List;public class ListTest1 {public static void main(String[] args) {//1、创建一个ArrayList集合对象有序、可重复、有索引ListString list new ArrayList(); //一行经典代码设计到多态优雅用的多list.add(aaa);list.add(bbb);list.add(ccc);list.add(ddd);System.out.println(list);//2、public void add(int index, E element): 在某个索引位置插入元素。list.add(2,chacha);System.out.println(list);// 3.public E remove(int index): 根据索引删除元素,返回被删除元素System.out.println(list.remove(2));System.out.println(list);// 4.public E get(int index): 返回集合中指定位置的元素。System.out.println(list.get(2));// 5.public E set(int index, E element): 修改索引位置处的元素,修改成功后会返回原来的数据System.out.println();System.out.println(list.set(2, gaigai));System.out.println(list);}
}//
[aaa, bbb, ccc, ddd]
[aaa, bbb, chacha, ccc, ddd]
chacha
[aaa, bbb, ccc, ddd]
cccccc
[aaa, bbb, gaigai, ddd]
List的遍历方式
List集合相比于前面的Collection多了一种可以通过索引遍历的方式所以List集合遍历方式一共有四种
普通for循环只因为List有索引迭代器增强forLambda表达式
package list;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class ListTest2 {public static void main(String[] args) {ListString list new ArrayList();list.add(糖宝宝);list.add(蜘蛛精);list.add(至尊宝);//1for循环for (int i 0; i list.size(); i) {//i0,1,2...System.out.println(list.get(i));}//2迭代器。IteratorString it list.iterator();while (it.hasNext()) {System.out.println(it.next());}//3增强for循环foreach遍历for (String s : list) {//s0,1,2...System.out.println(s);}//4JDK 1.8开始之后的Lambda表达式list.forEach(s - {System.out.println(s);});}
}
ArrayList集合的底层原理
ArrayList和LinkedList底层采用的数据结构不同应用场景也不同
所谓数据结构就是存储、组织数据的方式
ArrayList集合的底层原理 基于数组实现数组的特点查询快、增删慢 特点 查询速度快注意是根据索引查询数据快查询数据通过地址值和索引定位查询任意数据耗时相同。删除效率低可能需要把后面很多的数据进行前移。添加效率极低可能需要把后面很多的数据后移再添加元素或者也可能需要进行数组的扩容。 原理 利用无参构造器创建的集合会在底层创建一个默认长度为0的数组添加第一个元素时底层会创建一个新的长度为10的数组存满时会扩容1.5倍然后把原数组的数据迁移到新数组里如果一次添加多个元素1.5倍还放不下则新创建数组的长度以实际为准 注意数组扩容并不是在原数组上扩容原数组是不可以扩容的底层是创建一个新数组然后把原数组中的元素全部复制到新数组中去。
ArrayList集合适合的应用场景
1、ArrayList适合根据索引查询数据比如根据随机索引取数据高效或者数据量不是很大时
2、ArrayList不适合数据量大的同时 又要频繁的讲行增删操作
LinkedList集合的底层原理
LinkedList集合的底层原理
基于双链表实现链表的特点查询慢无论查询哪个数据都要从头开始找、增删快特点查询慢增删相对较快但对首尾元素进行增删改查的速度是极快的。 LinkedList新增特有方法
LinkedList新增了很多首尾操作的特有方法。
方法名称说明public void addFirst(E e)在该列表开头插入指定的元素public void addLast(E e)将指定的元素追加到此列表的末尾public E getFirst()返回此列表中的第一个元素public E getLast()返回此列表中的最后一个元素public E removeFirst()从此列表中删除并返回第一个元素public E removeLast()从此列表中删除并返回最后一个元素
LinkedList集合适合的应用场景
场景一可以用来设计队列
先进先出后进后出。排号
只是在首尾增删元素用LinkedList来实现很合适
// 1、创建一个队列。LinkedListString queue new LinkedList();// 入队queue.addLast(1);queue.addLast(2);queue.addLast(3);queue.addLast(4);System.out.println(queue);// 出队System.out.println(queue.removeFirst());System.out.println(queue.removeFirst());System.out.println(queue.removeFirst());System.out.println(queue);//
[1, 2, 3, 4]
1
2
3
[4]场景二可以用来设计栈
先进后出后进先出。
数据进入栈模型的过程称为压/进栈(push)
数据离开栈模型的过程称为弹/出栈(pop)
只是在首部增删云素用LinkedList来实现很合适
// 2、创建一个栈对象。LinkedListString stack new LinkedList();// 压栈(push)stack.addFirst(a);stack.addFirst(b);stack.addFirst(c);stack.addFirst(d);System.out.println(stack);// 出栈(pop)System.out.println(stack.removeFirst());System.out.println(stack.removeFirst());System.out.println(stack.removeFirst());System.out.println(stack.removeFirst());System.out.println(stack);//
[d, c, b, a]
d
c
b
a
[]但是java对于栈有专门的方法
// 2、创建一个栈对象。LinkedListString stack new LinkedList();
// 压栈(push) 等价于 addFirst()stack.push(第1颗子弹);stack.push(第2颗子弹);stack.push(第3颗子弹);stack.push(第4颗子弹);System.out.println(stack);
// 出栈(pop) 等价于 removeFirst()System.out.println(stack.pop());System.out.println(stack.pop());System.out.println(stack);Set集合
Set集合的特点
无序(添加数据的顺序和获取出的数据顺序不一致) 不重复 无索引;
HashSet : 无序、不重复、无索引。LinkedHashSet有序、不重复、无索引。TreeSet排序、不重复、无索引。 Set set new HashSet(); //创建了一个HashSet的集合对象。 一行经典代码 package set;import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;public class SetTest1 {public static void main(String[] args) {// 1、创建一个Set集合的对象
// SetInteger set new HashSet(); //创建了一个HashSet的集合对象。 一行经典代码 HashSet: 无序 不重复 无索引
// SetInteger set new LinkedHashSet(); //LinkedHashSet: 有序 不重复 无索引SetInteger set new TreeSet(); //TreeSet: 可排序默认升序 不重复 无索引set.add(444);set.add(111);set.add(333);set.add(222);set.add(555);set.add(333);System.out.println(set);}
}
//
[555, 444, 333, 222, 111] HashSet
[444, 111, 333, 222, 555] LinkedHashSet
[111, 222, 333, 444, 555] TreeSet注意
Set要用到的常用方法基本上就是Collection提供的自己几乎没有额外新增一些常用功能
HashSet集合的底层逻辑
HashSet : 无序、不重复、无索引
前导知识
哈希值 就是一个int类型的数值Java中每个对象都有一个哈希值。 Java中的所有对象都可以调用Obejct类提供的hashCode方法返回该对象自己的哈希值。 public int hashCode() : 返回对象的哈希码值
对象哈希值的特点
同一个对象多次调用hashCode()方法返回的哈希值是相同的。不同的对象它们的哈希值一般不相同但也有可能会相同(哈希碰撞)。
哈希表
JDK8以前哈希表 数组链表JDK8以后哈希表 数组链表红黑树 JDK8之前 默认加载因子为0.75的意思是一旦数组中的数据占满了数组长度的0.75倍了就开始扩容扩容到原数组的2倍然后把原数组的数据放到新数组里 JDK8开始当链表长度超过8且数组长度64时自动将链表转成红黑树 数据结构树
二叉树-》二叉查找树-》平衡二叉树-》红黑树
二叉树分为普通二叉树没啥用二叉查找树左小右大一样不放 二叉查找树存在的问题当数据已经是排好序的导致查询的性能与单链表一样查询速度变慢
在满足查找二叉树的大小规则下让树尽可能矮小以此提高查数据的性能。所以有了平衡二叉树 红黑树就是可以自平衡的二叉树。红黑树是一种增删改查数据性能相对都较好的结构。 HashSet集合底层原理
是基于哈希表实现的哈希表是一种增删改查数据性能都较好的数据结构
HashSet集合去重复的机制
HashSet集合默认不能对内容一样的两个不同对象去重复
比如内容一样的两个学生对象存入到HashSet集合中去HashSet集合是不能去重复的因为比较的是哈希地址内容一样哈希地址不一定一样。
如何让HashSet集合能够实现对内容一样的两个不同对象也能去重复
结论如果希望Set集合认为2个内容一样的对象是重复的必须重写对象的hashCode()和equals()方法右键generate-equals() and hashCode()-一路next,finish
LinkedHashSet集合的底层逻辑
LinkedHashSet有序、不重复、无索引
依然是基于哈希表**(数组、链表、红黑树)**实现的。但是它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置。 缺点就是更占内存空间换时间
TreeSet集合
TreeSet不重复、无索引、可排序默认升序排序 按照元素的大小由小到大排序
底层是基于红黑树实现的排序。 排序规则 对于数值类型Integer , Double默认按照数值本身的大小进行升序排序。对于字符串类型默认按照首字符的编号升序排序。对于自定义类型如Student对象TreeSet默认是无法直接排序的。
如果往TreeSet集合中存储自定义类型的元素比如说Student类型则需要我们自己指定排序规则否则会出现异常。
比如此时运行代码会直接报错。原因是TreeSet不知道按照什么条件对Student对象来排序。 TreeSet集合存储自定义类型的对象时必须指定排序规则支持如下两种方式来指定比较规则。 自定义排序规则 方式一 让自定义的类如学生类实现Comparable接口重写里面的compareTo方法来指定比较规则。
方式二 通过调用TreeSet集合有参数构造器可以设置Comparator对象比较器对象)用于指定比较规则。
public TreeSet(Comparator? super E comparator)方法一重写compareTo方法 方法二Comparator对象 Lambda简化后 注意如果有自定义了两个比较规则Treeset会采取就近选择自带的比较器对象进行比较 两种方式中关于返回值的规则 如果认为第一个元素 第二个元素 返回正整数即可。如果认为第一个元素 第二个元素返回负整数即可。如果认为第一个元素 第二个元素返回0即可此时Treeset集合只会保留一个元素认为两者重复。 ✅总结场景选择 注意事项集合的并发修改异常问题
集合的并发修改异常就是使用迭代器遍历集合时又同时在删除集合中的数据程序就会出现并发修改异常的错误。
ListString list new ArrayList();
list.add(王麻子);
list.add(小李子);
list.add(李爱花);
list.add(张全蛋);
list.add(晓李);
list.add(李玉刚);
System.out.println(list); // [王麻子, 小李子, 李爱花, 张全蛋, 晓李, 李玉刚]//需求找出集合中带李字的姓名并从集合中删除
IteratorString it list.iterator();
while(it.hasNext()){String name it.next();if(name.contains(李)){list.remove(name);}
}
System.out.println(list);运行上面的代码会出现下面的异常。这就是并发修改异常 为什么会出现这个异常呢那是因为迭代器遍历机制规定迭代器遍历集合的同时不允许集合自己去增删元素否则就会出现这个异常。
怎么解决这个问题呢不使用集合的删除方法而是使用迭代器的删除方法代码如下
ListString list new ArrayList();
list.add(王麻子);
list.add(小李子);
list.add(李爱花);
list.add(张全蛋);
list.add(晓李);
list.add(李玉刚);
System.out.println(list); // [王麻子, 小李子, 李爱花, 张全蛋, 晓李, 李玉刚]//需求找出集合中带李字的姓名并从集合中删除
IteratorString it list.iterator();
while(it.hasNext()){String name it.next();if(name.contains(李)){//list.remove(name);it.remove(); //当前迭代器指向谁就删除谁✅}
}
System.out.println(list);由于增强for循环遍历集合就是迭代器遍历集合的简化写法因此使用增强for循环遍历集合又在同时删除集合中的数据时程序也会出现并发修改异常的错误。
怎么保证遍历集合同时删除数据时不出bug
使用迭代器遍历集合用迭代器自己的删除方法删除数据即可。如果能用for循环遍历时可以倒着遍历并删除或者从前往后遍历但删除元素后做**i --**操作。
Collection的其他相关知识
可变参数 什么是可变参数 可变参数就是一种特殊形参定义在方法、构造器的形参列表里它可以让方法接收多个同类型的实际参数。 什么格式 格式是数据类型…参数名称
public class ParamTest{public static void main(String[] args){//不传递参数下面的nums长度则为0, 打印元素是[]test(); //传递3个参数下面的nums长度为3打印元素是[10, 20, 30]test(10,20,30); //传递一个数组下面数组长度为4打印元素是[10,20,30,40] int[] arr new int[]{10,20,30,40}test(arr); }public static void test(int...nums){//可变参数在方法内部本质上是一个数组System.out.println(nums.length);System.out.println(Arrays.toString(nums));System.out.println(----------------);}
}注意事项 最后还有一些错误写法需要让大家写代码时注意一下不要这么写哦
一个形参列表中只能有一个可变参数否则会报错一个形参列表中如果多个参数可变参数需要写在最后否则会报错可变参数对外接收数据但是在方法内部本质上是一个数组 可变参数的特点和好处 特点可以不传数据给它可以传一个或者同时传多个数据给它也可以传一个数组给它。
好处常常用来灵活的接收数据。
Collections工具类
是一个用来操作集合的工具类
注意Collections并不是集合它比Collection多了一个s一般后缀为s的类很多都是工具类。这里的Collections是用来操作Collection的工具类。
Collections提供的常用静态方法
方法名称说明public static boolean addAll(Collection? super T c, T… elements)给集合批量添加元素。Collection下的种类都能用public static void shuffle(List? list)打乱List集合中的元素顺序。仅用于List集合public static void sort(List list)对List集合中的元素进行升序排序public static void sort(List listComparator? super T c)对List集合中元素按照比较器对象指定的规则进行排序
public class CollectionsTest{public static void main(String[] args){//1.public static T boolean addAll(Collection? super T c, T...e)为集合批量添加数据ListString names new ArrayList();Collections.addAll(names, 张三,王五,李四, 张麻子);System.out.println(names);//2.public static void shuffle(List? list)对集合打乱顺序Collections.shuffle(names);System.out.println(names);//3.public static T void short(ListT list): 对List集合排序ListInteger list new ArrayList();list.add(3);list.add(5);list.add(2);Collections.sort(list);System.out.println(list);//4、使用调用sort方法传递比较器Collections.sort(students, new ComparatorStudent(){Overridepublic int compare(Student o1, Student o2){return o1.getAge()-o2.getAge();}
});
System.out.println(students);}
}综合案例
斗地主
➡️Map集合
概述 什么是Map集合 所谓双列集合就是说集合中的元素是一对一对的。Map集合中的每一个元素是以keyvalue的形式存在的一个keyvalue就称之为一个键值对而且在Java中有一个类叫Entry类Entry的对象用来表示键值对对象。
Map集合称为双列集合格式{key1value1 , key2value2 , key3value3 , …} 一次需要存一对数据做为一个元素.Map集合的每个元素“keyvalue”称为一个键值对/键值对对象/一个Entry对象Map集合也被叫做“键值对集合”Map集合的所有键是不允许重复的但值可以重复键和值是一一对应的每一个键只能找到自己对应的值 Map集合在什么业务场景下使用 需要存储一一对应的数据时就可以考虑使用Map集合来做。 Map集合体系 Map集合体系的特点 注意Map系列集合的特点都是由键决定的值只是一个附属品值是不做要求的
HashMap由键决定特点: 无序、不重复、无索引 用的最多LinkedHashMap 由键决定特点有序、不重复、无索引。TreeMap 由键决定特点按照大小默认升序排序**、**不重复、无索引。 MapString, Integer map new HashMap(); // 一行经典代码 public class MapTest1 {public static void main(String[] args) {// MapString, Integer map new HashMap(); // 一行经典代码。 按照键 无序不重复无索引。MapString, Integer map new LinkedHashMap(); // 有序不重复无索引。map.put(手表, 100);map.put(手表, 220); // 后面重复的数据会覆盖前面的数据键map.put(手机, 2);map.put(Java, 2);map.put(null, null);System.out.println(map);MapInteger, String map1 new TreeMap(); // 可排序不重复无索引map1.put(23, Java);map1.put(23, MySQL);map1.put(19, 李四);map1.put(20, 王五);System.out.println(map1);}
}常用方法
由于Map是所有双列集合的父接口所以我们只需要学习Map接口中每一个方法是什么含义那么所有的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 keySet()获取全部键的集合public Collection values()获取Map集合的全部值
public class MapTest2 {public static void main(String[] args) {// 1.添加元素: 无序不重复无索引。MapString, Integer map new HashMap();map.put(手表, 100);map.put(手表, 220);map.put(手机, 2);map.put(Java, 2);map.put(null, null);System.out.println(map);// map {nullnull, 手表220, Java2, 手机2}// 2.public int size():获取集合的大小System.out.println(map.size());// 3、public void clear():清空集合//map.clear();//System.out.println(map);// 4.public boolean isEmpty(): 判断集合是否为空为空返回true ,反之System.out.println(map.isEmpty());// ✅5.public V get(Object key)根据键获取对应值int v1 map.get(手表);System.out.println(v1);System.out.println(map.get(手机)); // 2System.out.println(map.get(张三)); // null// 6. public V remove(Object key)根据键删除整个元素(删除键会返回键的值)System.out.println(map.remove(手表));System.out.println(map);// 7.public boolean containsKey(Object key): 判断是否包含某个键 包含返回true ,反之。精确匹配System.out.println(map.containsKey(手表)); // falseSystem.out.println(map.containsKey(手机)); // trueSystem.out.println(map.containsKey(java)); // falseSystem.out.println(map.containsKey(Java)); // true// 8.public boolean containsValue(Object value): 判断是否包含某个值。System.out.println(map.containsValue(2)); // trueSystem.out.println(map.containsValue(2)); // false// 9.public SetK keySet(): 获取Map集合的全部键。SetString keys map.keySet();System.out.println(keys);// 10.public CollectionV values(); 获取Map集合的全部值。CollectionInteger values map.values();System.out.println(values);// 11.把其他Map集合的数据倒入到自己集合中来。(拓展)MapString, Integer map1 new HashMap();map1.put(java1, 10);map1.put(java2, 20);MapString, Integer map2 new HashMap();map2.put(java3, 10);map2.put(java2, 222);map1.putAll(map2); // putAll把map2集合中的元素全部倒入一份到map1集合中去。System.out.println(map1); //{java310, java2222, java110}System.out.println(map2); //{java310, java2222}}
}遍历方法 方法1键找值 需要用到Map的如下方法 方法名称说明public Set keySet()获取所有键的集合public V get(Object key)根据键获取其对应的值
/*** 目标掌握Map集合的遍历方式1键找值*/
public class MapTest1 {public static void main(String[] args) {// 准备一个Map集合。MapString, Double map new HashMap();map.put(蜘蛛精, 162.5);map.put(蜘蛛精, 169.8);map.put(紫霞, 165.8);map.put(至尊宝, 169.5);map.put(牛魔王, 183.6);System.out.println(map);// map {蜘蛛精169.8, 牛魔王183.6, 至尊宝169.5, 紫霞165.8}// 1、获取Map集合的全部键SetString keys map.keySet();// System.out.println(keys);// [蜘蛛精, 牛魔王, 至尊宝, 紫霞]// key// 2、遍历全部的键根据键获取其对应的值for (String key : keys) {// 根据键获取对应的值double value map.get(key);System.out.println(key value);}}
}方法2键值对
Map集合是用来存储键值对的而每一个键值对实际上是一个Entry对象。
这里Map集合的第二种方式是直接获取每一个Entry对象把Entry存储扫Set集合中去再通过Entry对象获取键和值。 用到的方法 Map提供的方法说明SetMap.EntryK, V entrySet()获取所有“键值对”的集合
Map.Entry提供的方法说明K getKey()获取键V getValue()获取值 /*** 目标掌握Map集合的第二种遍历方式键值对。*/
public class MapTest2 {public static void main(String[] args) {MapString, Double map new HashMap();map.put(蜘蛛精, 169.8);map.put(紫霞, 165.8);map.put(至尊宝, 169.5);map.put(牛魔王, 183.6);System.out.println(map);// map {蜘蛛精169.8, 牛魔王183.6, 至尊宝169.5, 紫霞165.8}// entries [(蜘蛛精169.8), (牛魔王183.6), (至尊宝169.5), (紫霞165.8)]// entry (蜘蛛精169.8)// entry (牛魔王183.6)// ...// 1、调用Map集合提供entrySet方法把Map集合转换成键值对类型的Set集合SetMap.EntryString, Double entries map.entrySet();for (Map.EntryString, Double entry : entries) {String key entry.getKey();double value entry.getValue();System.out.println(key ---- value);}}
}方法3Lambda 需要用到Map的如下方法 方法名称说明default void forEach(BiConsumer? super K, ? super V action)结合lambda遍历Map集合
/*** 目标掌握Map集合的第三种遍历方式Lambda。*/
public class MapTest3 {public static void main(String[] args) {MapString, Double map new HashMap();map.put(蜘蛛精, 169.8);map.put(紫霞, 165.8);map.put(至尊宝, 169.5);map.put(牛魔王, 183.6);System.out.println(map);// map {蜘蛛精169.8, 牛魔王183.6, 至尊宝169.5, 紫霞165.8}//✅遍历map集合传递Lambda表达式map.forEach(( k, v) - {System.out.println(k ---- v);});//上面的原始的遍历架子//遍历map集合传递匿名内部类map.forEach(new BiConsumerString, Double() {Overridepublic void accept(String k, Double v) {System.out.println(k ---- v);}});}
}案例 Map集合-统计投票人数 public class MapDemo4 {public static void main(String[] args) {// 1、把80个学生选择的景点数据拿到程序中来。ListString data new ArrayList();String[] selects {A, B, C, D};Random r new Random();for (int i 1; i 80; i) {// 每次模拟一个学生选择一个景点存入到集合中去。int index r.nextInt(4); // 0 1 2 3data.add(selects[index]);}System.out.println(data);// 2、开始统计每个景点的投票人数// 准备一个Map集合用于统计最终的结果MapString, Integer result new HashMap();// 3、开始遍历80个景点数据for (String s : data) {// 问问Map集合中是否存在该景点if(result.containsKey(s)){// 说明这个景点之前统计过。其值1. 存入到Map集合中去result.put(s, result.get(s) 1);}else {// 说明这个景点是第一次统计存入景点1result.put(s, 1);}}System.out.println(result);}
}需要存储一一对应的数据时就可以考虑使用Map集合来做 HashMap
HashMap由键决定特点: 无序、不重复、无索引 用的最多 HashMap跟HashSet的底层原理是一模一样的都是基于哈希表实现的。 实际上原来学的Set系列集合的底层就是基于Map实现的只是Set集合中的元素只要键数据不要值数据而已。 哈希表 JDK8之前哈希表 数组链表 JDK8开始哈希表 数组链表红黑树 哈希表是一种增删改查数据性能都较好的数据结构。
HashMap底层原理 利用键计算哈希值跟值无关。 如何处理哈希碰撞 JDK8之前如果新元素和老元素位置一样新元素占据老元素位置老元素挂到新元素下面 JDK8之后新元素直接挂到老元素下面 挂的长度超过8数组长度64自动转成红黑树 基于哈希表实现的增删改查都较好 HashMap的键依赖*hashCode*方法和equals方法保证键的唯一 用hashCode算位置用equals算内容如果都一样则两个元素一样 如果键存储的是自定义类型的对象可以通过重写hashCode和equals方法这样可以保证多个对象内容一样时HashMap集合就能认为是重复的。
LinkedHashMap
LinkedHashMap 由键决定特点有序、不重复、无索引。
public static void main(String[] args) {// MapString, Integer map new HashMap(); // 按照键 无序不重复无索引。LinkedHashMapString, Integer map new LinkedHashMap(); // 按照键 有序不重复无索引。map.put(手表, 100);map.put(手表, 220);map.put(手机, 2);map.put(Java, 2);map.put(null, null);System.out.println(map);}//Out
{nullnull手表220Java2手机2} //HashMap
{手表220手机2Java2nullnull} //LinkedHashMapLinkedHashMap底层原理
底层数据结构依然是基于哈希表实现的只是每个键值对元素又额外的多了一个双链表的机制记录元素顺序(保证有序)。
和LinkedHashSet很像
实际上原来学习的LinkedHashSet集合的底层原理就是LinkedHashMap。 增删改查性能都还可以有序不重复选LinkedHashMap TreeMap
特点不重复、无索引、可排序(按照键的大小默认升序排序只能对键排序)
原理TreeMap跟TreeSet集合的底层原理是一样的都是基于红黑树实现的排序。
TreeMap集合同样也支持两种方式来指定排序规则
让类实现Comparable接口重写比较规则。TreeMap集合有一个有参数构造器支持创建Comparator比较器对象以便用来指定比较规则。
排序方式1写一个Student类让Student类实现Comparable接口
//第一步先让Student类实现Comparable接口
public class Student implements ComparableStudent{private String name;private int age;private double height;//无参数构造方法public Student(){}//全参数构造方法public Student(String name, int age, double height){this.namename;this.ageage;this.heightheight;}//...get、set、toString()方法自己补上..//按照年龄进行比较只需要在方法中让this.age和o.age相减就可以。/*原理在往TreeSet集合中添加元素时add方法底层会调用compareTo方法根据该方法的结果是正数、负数、还是零决定元素放在后面、前面还是不存。*/Overridepublic int compareTo(Student o) {//this表示将要添加进去的Student对象//o: 表示集合中已有的Student对象return this.age-o.age;}
}排序方式2在创建TreeMap集合时直接传递Comparator比较器对象。
/*** 目标掌握TreeMap集合的使用。*/
public class Test3TreeMap {public static void main(String[] args) {MapStudent, String map new TreeMap(new ComparatorStudent() {Overridepublic int compare(Student o1, Student o2) {return Double.compare(o1.getHeight(), o2.getHeight());}});
// MapStudent, String map new TreeMap(( o1, o2) - Double.compare(o2.getHeight(), o1.getHeight()));map.put(new Student(蜘蛛精, 25, 168.5), 盘丝洞);map.put(new Student(蜘蛛精, 25, 168.5), 水帘洞);map.put(new Student(至尊宝, 23, 163.5), 水帘洞);map.put(new Student(牛魔王, 28, 183.5), 牛头山);System.out.println(map);}
}这种方式都可以对TreeMap集合中的键排序。注意只有TreeMap的键才能排序HashMap键不能排序。
补充知识集合的嵌套
集合的嵌套就是集合中的元素又是一个集合 案例分析
1.从需求中我们可以看到有三个省份每一个省份有多个城市我们可以用一个Map集合的键表示省份名称而值表示省份有哪些城市
2.而又因为一个省份有多个城市同一个省份的多个城市可以再用一个List集合来存储。所以Map集合的键是String类型而指是List集合类型HashMapString, ListString map new HashMap();代码如下
/*** 目标理解集合的嵌套。* 江苏省 南京市,扬州市,苏州市“,无锡市,常州市* 湖北省 武汉市,孝感市,十堰市,宜昌市,鄂州市* 河北省 石家庄市,唐山市, 邢台市, 保定市, 张家口市*/
public class Test {public static void main(String[] args) {// 1、定义一个Map集合存储全部的省份信息和其对应的城市信息。MapString, ListString map new HashMap();ListString cities1 new ArrayList();Collections.addAll(cities1, 南京市,扬州市,苏州市 ,无锡市,常州市);map.put(江苏省, cities1);ListString cities2 new ArrayList();Collections.addAll(cities2, 武汉市,孝感市,十堰市,宜昌市,鄂州市);map.put(湖北省, cities2);ListString cities3 new ArrayList();Collections.addAll(cities3, 石家庄市,唐山市, 邢台市, 保定市, 张家口市);map.put(河北省, cities3);System.out.println(map);ListString cities map.get(湖北省);for (String city : cities) {System.out.println(city);}map.forEach((p, c) - {System.out.println(p ----- c);});}
}Stream流
JDK8开始最大的改变Lambda, Stream
认识Stream
也叫Stream流是Jdk8开始新增的一套API (java.util.stream.*)可以用于操作集合或者数组的数据。
优势 Stream流大量的结合了Lambda的语法风格来编程提供了一种更加强大更加简单的方式操作集合或者数组中的数据代码更简洁可读性更好。 public class StreamTest1 {public static void main(String[] args) {ListString names new ArrayList();Collections.addAll(names, 张三丰,张无忌,周芷若,赵敏,张强);System.out.println(names);// names [张三丰, 张无忌, 周芷若, 赵敏, 张强]// name// 找出姓张且是3个字的名字存入到一个新集合中去。ListString list new ArrayList();for (String name : names) {if(name.startsWith(张) name.length() 3){list.add(name);}}System.out.println(list);// 开始使用Stream流来解决这个需求。ListString list2 names.stream().filter(s - s.startsWith(张)).filter(a - a.length()3).collect(Collectors.toList());System.out.println(list2);}
}Stream流的使用步骤 Stream的常用方法 1、获取Stream流
获取 集合 的Stream流
Collection提供的如下方法说明default Stream stream()获取当前集合对象的Stream流
获取 数组 的Stream流
Arrays类提供的如下 方法说明public static Stream stream(T[] array)获取当前数组的Stream流
Stream类提供的如下 方法说明public static Stream of(T… values)获取当前接收数据的Stream流
/*** 目标掌握Stream流的创建。*/
public class StreamTest2 {public static void main(String[] args) {// 1、如何获取List集合的Stream流ListString names new ArrayList();Collections.addAll(names, 张三丰,张无忌,周芷若,赵敏,张强);StreamString stream names.stream();// 2、如何获取Set集合的Stream流SetString set new HashSet();Collections.addAll(set, 刘德华,张曼玉,蜘蛛精,马德,德玛西亚);StreamString stream1 set.stream();stream1.filter(s - s.contains(德)).forEach(s - System.out.println(s));// 3、如何获取Map集合的Stream流MapString, Double map new HashMap();map.put(古力娜扎, 172.3);map.put(迪丽热巴, 168.3);map.put(马尔扎哈, 166.3);map.put(卡尔扎巴, 168.3);SetString keys map.keySet();StreamString ks keys.stream();CollectionDouble values map.values();StreamDouble vs values.stream();SetMap.EntryString, Double entries map.entrySet();StreamMap.EntryString, Double kvs entries.stream();kvs.filter(e - e.getKey().contains(巴)).forEach(e - System.out.println(e.getKey() -- e.getValue()));// 4、如何获取数组的Stream流String[] names2 {张翠山, 东方不败, 唐大山, 独孤求败};StreamString s1 Arrays.stream(names2);StreamString s2 Stream.of(names2);}
}
2、Stream流常见的中间方法
中间方法指的是调用完成后会返回新的Stream流可以继续使用(支持链式编程)。 /** 目标掌握Stream流提供的常见中间方法。*/
public class StreamTest3 {public static void main(String[] args) {ListDouble scores new ArrayList();Collections.addAll(scores, 88.5, 100.0, 60.0, 99.0, 9.5, 99.6, 25.0);// 需求1找出成绩大于等于60分的数据并升序后再输出。scores.stream().filter(s - s 60).sorted().forEach(s - System.out.println(s));ListStudent students new ArrayList();Student s1 new Student(蜘蛛精, 26, 172.5);Student s2 new Student(蜘蛛精, 26, 172.5);Student s3 new Student(紫霞, 23, 167.6);Student s4 new Student(白晶晶, 25, 169.0);Student s5 new Student(牛魔王, 35, 183.3);Student s6 new Student(牛夫人, 34, 168.5);Collections.addAll(students, s1, s2, s3, s4, s5, s6);// 需求2找出年龄大于等于23,且年龄小于等于30岁的学生并按照年龄降序输出.students.stream().filter(s - s.getAge() 23 s.getAge() 30).sorted((o1, o2) - o2.getAge() - o1.getAge()).forEach(s - System.out.println(s));// 需求3取出身高最高的前3名学生并输出。students.stream().sorted((o1, o2) - Double.compare(o2.getHeight(), o1.getHeight())).limit(3).forEach(System.out::println);System.out.println(-----------------------------------------------);// 需求4取出身高倒数的2名学生并输出。 s1 s2 s3 s4 s5 s6students.stream().sorted((o1, o2) - Double.compare(o2.getHeight(), o1.getHeight())).skip(students.size() - 2).forEach(System.out::println);// 需求5找出身高超过168的学生叫什么名字要求去除重复的名字再输出。students.stream().filter(s - s.getHeight() 168).map(Student::getName).distinct().forEach(System.out::println);//简化前.map(s - s.getName())// distinct去重复自定义类型的对象希望内容一样就认为重复重写hashCode,equalsstudents.stream().filter(s - s.getHeight() 168).distinct().forEach(System.out::println);StreamString st1 Stream.of(张三, 李四);StreamString st2 Stream.of(张三2, 李四2, 王五);StreamString allSt Stream.concat(st1, st2);allSt.forEach(System.out::println);}
}3、Stream流常见的终结方法
终结方法指的是调用完成后不会返回新Stream了没法继续使用流了。 有的需求需要我们把结果放到集合或者数组中去所以需要收集Stream流
收集Stream流就是把Stream流操作后的结果转回到集合或者数组中去返回。
Stream流方便操作集合/数组的手段 集合/数组才是开发中的目的。
Stream提供的常用终结方法说明R collect(Collector collector)把流处理后的结果收集到一个指定的集合中去Object[] toArray()把流处理后的结果收集到一个数组中去
Collectors工具类提供了具体的收集方式说明public static Collector toList()把元素收集到List集合中public static Collector toSet()把元素收集到Set集合中public static Collector toMap(Function keyMapper , Function valueMapper)把元素收集到Map集合中
/*** 目标Stream流的终结方法*/
public class StreamTest4 {public static void main(String[] args) {ListStudent students new ArrayList();Student s1 new Student(蜘蛛精, 26, 172.5);Student s2 new Student(蜘蛛精, 26, 172.5);Student s3 new Student(紫霞, 23, 167.6);Student s4 new Student(白晶晶, 25, 169.0);Student s5 new Student(牛魔王, 35, 183.3);Student s6 new Student(牛夫人, 34, 168.5);Collections.addAll(students, s1, s2, s3, s4, s5, s6);// 需求1请计算出身高超过168的学生有几人。long size students.stream().filter(s - s.getHeight() 168).count();System.out.println(size);// 需求2请找出身高最高的学生对象并输出。Student s students.stream().max((o1, o2) - Double.compare(o1.getHeight(), o2.getHeight())).get();System.out.println(s);// 需求3请找出身高最矮的学生对象并输出。Student ss students.stream().min((o1, o2) - Double.compare(o1.getHeight(), o2.getHeight())).get();System.out.println(ss);// 需求4请找出身高超过170的学生对象并放到一个新集合中去返回。// 流只能收集一次。ListStudent students1 students.stream().filter(a - a.getHeight() 170).collect(Collectors.toList());System.out.println(students1);SetStudent students2 students.stream().filter(a - a.getHeight() 170).collect(Collectors.toSet());System.out.println(students2);// 需求5请找出身高超过170的学生对象并把学生对象的名字和身高存入到一个Map集合返回。MapString, Double map students.stream().filter(a - a.getHeight() 170).distinct().collect(Collectors.toMap(a - a.getName(), a - a.getHeight()));System.out.println(map);// Object[] arr students.stream().filter(a - a.getHeight() 170).toArray();Student[] arr students.stream().filter(a - a.getHeight() 170).toArray(len - new Student[len]);System.out.println(Arrays.toString(arr));}
}