作者主页:编程指南针
作者简介:Java领域优质创作者、优快云博客专家
、优快云内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师主要内容:Java项目、Python项目、前端项目、人工智能与大数据、简历模板、学习资料、面试题库、技术互助
收藏点赞不迷路 关注作者有好处
文末获取源码
一、Collections工具类
各位同学,前面我们已经把Collection家族的集合都学习完了。为了更加方便的对Collection集合进行操作,今天我们还要学习一个操作Collection集合的工具类,叫做Collections。但是Collections工具类中需要用到一个没有学过的小知识点,叫做可变参数,所以必须先学习这个前置知识可变参数,再学习Collections工具类,最后再利用这个工具类做一个综合案例。
1.1 可变参数
首先,我们来学习一下可变参数。关于可变参数我们首先要知道它是什么,然后要知道它的本质。搞清楚这两个问题,可变参数就算你学明白了。
可变参数是一种特殊的形式参数,定义在方法、构造器的形参列表处,它可以让方法接收多个同类型的实际参数。
可变参数在方法内部,本质上是一个数组
接下来,我们编写代码来演示一下
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("----------------");
}
}
最后还有一些错误写法,需要让大家写代码时注意一下,不要这么写哦!!!
一个形参列表中,只能有一个可变参数;否则会报错
一个形参列表中如果多个参数,可变参数需要写在最后;否则会报错
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JUnjG8sm-1690457662704)(assets/1667194652653.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TWyzAf13-1690457662706)(assets/1667194696892.png)]
1.2 Collections工具类
有了可变参数的基础,我们再学习Collections这个工具类就好理解了,因为这个工具类的方法中会用到可变参数。
注意Collections并不是集合,它比Collection多了一个s,一般后缀为s的类很多都是工具类。这里的Collections是用来操作Collection的工具类。它提供了一些好用的静态方法,如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QylsMsKj-1690457662707)(assets/1667195108724.png)]
我们把这些方法用代码来演示一下:
public class CollectionsTest{
public static void main(String[] args){
//1.public static <T> boolean addAll(Collection<? super T> c, T...e)
List<String> 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(List<T list): 对List集合排序
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(5);
list.add(2);
Collections.sort(list);
System.out.println(list);
}
}
上面我们往集合中存储的元素要么是Stirng类型,要么是Integer类型,他们本来就有一种自然顺序所以可以直接排序。但是如果我们往List集合中存储Student对象,这个时候想要对List集合进行排序自定义比较规则的。指定排序规则有两种方式,如下:
排序方式1:让元素实现Comparable接口,重写compareTo方法
比如现在想要往集合中存储Studdent对象,首先需要准备一个Student类,实现Comparable接口。
public class Student implements Comparable<Student>{
private String name;
private int age;
private double height;
//排序时:底层会自动调用此方法,this和o表示需要比较的两个对象
@Override
public int compareTo(Student o){
//需求:按照年龄升序排序
//如果返回正数:说明左边对象的年龄>右边对象的年龄
//如果返回负数:说明左边对象的年龄<右边对象的年龄,
//如果返回0:说明左边对象的年龄和右边对象的年龄相同
return this.age - o.age;
}
//...getter、setter、constructor..
}
然后再使用Collections.sort(list集合)
对List集合排序,如下:
//3.public static <T> void short(List<T list): 对List集合排序
List<Student> students = new ArrayList<>();
students.add(new Student("蜘蛛精",23,169.7));
students.add(new Student("紫霞",22,169.8));
students.add(new Student("紫霞",22,169.8));
students.add(new Student("至尊宝",26,169.5));
/*
原理:sort方法底层会遍历students集合中的每一个元素,采用排序算法,将任意两个元素两两比较;
每次比较时,会用一个Student对象调用compareTo方法和另一个Student对象进行比较;
根据compareTo方法返回的结果是正数、负数,零来决定谁大,谁小,谁相等,重新排序元素的位置
注意:这些都是sort方法底层自动完成的,想要完全理解,必须要懂排序算法才行;
*/
Collections.sort(students);
System.out.println(students);
排序方式2:使用调用sort方法是,传递比较器
/*
原理:sort方法底层会遍历students集合中的每一个元素,采用排序算法,将任意两个元素两两比较;
每次比较,会将比较的两个元素传递给Comparator比较器对象的compare方法的两个参数o1和o2,
根据compare方法的返回结果是正数,负数,或者0来决定谁大,谁小,谁相等,重新排序元素的位置
注意:这些都是sort方法底层自动完成的,不需要我们完全理解,想要理解它必须要懂排序算法才行.
*/
Collections.sort(students, new Comparator<Student>(){
@Override
public int compare(Student o1, Student o2){
return o1.getAge()-o2.getAge();
}
});
System.out.println(students);
1.3 斗地主案例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-efM7QA1E-1690457662709)(assets/1667306432458.png)]
我们先分析一下业务需求:
- 总共有54张牌,每一张牌有花色和点数两个属性、为了排序还可以再加一个序号
- 点数可以是:
“3”,"4","5","6","7","8","9","10","J","Q","K","A","2"
- 花色可以是:
“♣”,"♠","♥","♦"
- 斗地主时:三个玩家没人手里17张牌,剩余3张牌作为底牌
第一步:为了表示每一张牌有哪些属性,首先应该新建一个扑克牌的类
第二步:启动游戏时,就应该提前准备好54张牌
第三步:接着再完全洗牌、发牌、捋牌、看牌的业务逻辑
先来完成第一步,定义一个扑克类Card
public class Card {
private String number;
private String color;
// 每张牌是存在大小的。
private int size; // 0 1 2 ....
public Card() {
}
public Card(String number, String color, int size) {
this.number = number;
this.color = color;
this.size = size;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
@Override
public String toString() {
return color + number ;
}
}
再完成第二步,定义一个房间类,初始化房间时准备好54张牌
public class Room {
// 必须有一副牌。
private List<Card> allCards = new ArrayList<>();
public Room(){
// 1、做出54张牌,存入到集合allCards
// a、点数:个数确定了,类型确定。
String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
// b、花色:个数确定了,类型确定。
String[] colors = {"♠", "♥", "♣", "♦"};
int size = 0; // 表示每张牌的大小
// c、遍历点数,再遍历花色,组织牌
for (String number : numbers) {
// number = "3"
size++; // 1 2 ....
for (String color : colors) {
// 得到一张牌
Card c = new Card(number, color, size);
allCards.add(c); // 存入了牌
}
}
// 单独存入小大王的。
Card c1 = new Card("", "🃏" , ++size);
Card c2 = new Card("", "👲" , ++size);
Collections.addAll(allCards, c1, c2);
System.out.println("新牌:" + allCards);
}
}
最后完成第三步,定义一个启动游戏的方法,完成洗牌、发牌、捋牌、看牌的业务逻辑
/**
* 游戏启动
*/
public void start() {
// 1、洗牌: allCards
Collections.shuffle(allCards);
System.out.println("洗牌后:" + allCards);
// 2、发牌,首先肯定要定义 三个玩家。 List(ArrayList) Set(TreeSet)
List<Card> linHuChong = new ArrayList<>();
List<Card> jiuMoZhi = new ArrayList<>();
List<Card> renYingYing = new ArrayList<>();
// 正式发牌给这三个玩家,依次发出51张牌,剩余3张做为底牌。
// allCards = [♥3, ♣10, ♣4, ♥K, ♦Q, ♣2, 🃏, ♣8, ....
// 0 1 2 3 4 5 6 ... % 3
for (int i = 0; i < allCards.size() - 3; i++) {
Card c = allCards.get(i);
// 判断牌发给谁
if(i % 3 == 0){
// 请啊冲接牌
linHuChong.add(c);
}else if(i % 3 == 1){
// 请啊鸠来接牌
jiuMoZhi.add(c);
}else if(i % 3 == 2){
// 请盈盈接牌
renYingYing.add(c);
}
}
// 3、对3个玩家的牌进行排序
sortCards(linHuChong);
sortCards(jiuMoZhi);
sortCards(renYingYing);
// 4、看牌
System.out.println("啊冲:" + linHuChong);
System.out.println("啊鸠:" + jiuMoZhi);
System.out.println("盈盈:" + renYingYing);
List<Card> lastThreeCards = allCards.subList(allCards.size() - 3, allCards.size()); // 51 52 53
System.out.println("底牌:" + lastThreeCards);
jiuMoZhi.addAll(lastThreeCards);
sortCards(jiuMoZhi);
System.out.println("啊鸠抢到地主后:" + jiuMoZhi);
}
/**
* 集中进行排序
* @param cards
*/
private void sortCards(List<Card> cards) {
Collections.sort(cards, new Comparator<Card>() {
@Override
public int compare(Card o1, Card o2) {
// return o1.getSize() - o2.getSize(); // 升序排序
return o2.getSize() - o1.getSize(); // 降序排序
}
});
}
不要忘记了写测试类了,
public class GameDemo {
public static void main(String[] args) {
// 1、牌类。
// 2、房间
Room m = new Room();
// 3、启动游戏
m.start();
}
}
二、Map集合
2.1 Map概述体系
各位同学,前面我们已经把单列集合学习完了,接下来我们要学习的是双列集合。首先我们还是先认识一下什么是双列集合。
所谓双列集合,就是说集合中的元素是一对一对的。Map集合中的每一个元素是以key=value
的形式存在的,一个key=value
就称之为一个键值对,而且在Java中有一个类叫Entry类,Entry的对象用来表示键值对对象。
所有的Map集合有如下的特点:键不能重复,值可以重复,每一个键只能找到自己对应的值。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RvbWmMzG-1690457662726)(assets/1667308368751.png)]
下面我们先写一个Map集合,保存几个键值对,体验一下Map集合的特点
public class MapTest1 {
public static void main(String[] args) {
// Map<String, Integer> map = new HashMap<>(); // 一行经典代码。 按照键 无序,不重复,无索引。
Map<String, 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);
Map<Integer, String> map1 = new TreeMap<>(); // 可排序,不重复,无索引
map1.put(23, "Java");
map1.put(23, "MySQL");
map1.put(19, "李四");
map1.put(20, "王五");
System.out.println(map1);
}
}
Map集合也有很多种,在Java中使用不同的类来表示的,每一种Map集合其键的特点是有些差异的,值是键的一个附属值,所以我们只关注键的特点就可以了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ss5dwUPu-1690457662727)(assets/1667308506610.png)]
关于Map集合是什么,以及Map集合的体系我们先了解到这里,接下来就具体学习一下Map集合的通用方法。
2.2 Map集合的常用方法
各位同学,上节课我们已经认识了Map集合,接下来我们学习一下Map集合提供了那些方法供我们使用。由于Map是所有双列集合的父接口,所以我们只需要学习Map接口中每一个方法是什么含义,那么所有的Map集合方法你就都会用了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zycGFJyV-1690457662728)(assets/1667308854001.png)]
public class MapTest2 {
public static void main(String[] args) {
// 1.添加元素: 无序,不重复,无索引。
Map<String, 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 = {null=null, 手表=220, Java=2, 手机=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("手机")); // 2
System.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("手表")); // false
System.out.println(map.containsKey("手机")); // true
System.out.println(map.containsKey("java")); // false
System.out.println(map.containsKey("Java")); // true
// 8.public boolean containsValue(Object value): 判断是否包含某个值。
System.out.println(map.containsValue(2)); // true
System.out.println(map.containsValue("2")); // false
// 9.public Set<K> keySet(): 获取Map集合的全部键。
Set<String> keys = map.keySet();
System.out.println(keys);
// 10.public Collection<V> values(); 获取Map集合的全部值。
Collection<Integer> values = map.values();
System.out.println(values);
// 11.把其他Map集合的数据倒入到自己集合中来。(拓展)
Map<String, Integer> map1 = new HashMap<>();
map1.put("java1", 10);
map1.put("java2", 20);
Map<String, Integer> map2 = new HashMap<>();
map2.put("java3", 10);
map2.put("java2", 222);
map1.putAll(map2); // putAll:把map2集合中的元素全部倒入一份到map1集合中去。
System.out.println(map1);
System.out.println(map2);
}
}
2.3 Map集合遍历方式1
Map集合一共有三种遍历方式,我们先来学习第一种,他需要用到下面的两个方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0H6t1JOx-1690457662730)(assets/1667308962740.png)]
/**
* 目标:掌握Map集合的遍历方式1:键找值
*/
public class MapTest1 {
public static void main(String[] args) {
// 准备一个Map集合。
Map<String, 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集合的全部键
Set<String> keys = map.keySet();
// System.out.println(keys);
// [蜘蛛精, 牛魔王, 至尊宝, 紫霞]
// key
// 2、遍历全部的键,根据键获取其对应的值
for (String key : keys) {
// 根据键获取对应的值
double value = map.get(key);
System.out.println(key + "=====>" + value);
}
}
}
2.4 Map集合遍历方式2
各位同学,接下来我们学习Map集合的第二种遍历方式,这种遍历方式更加符合面向对象的思维。
前面我们给大家介绍过,Map集合是用来存储键值对的,而每一个键值对实际上是一个Entry对象。
这里Map集合的第二种方式,是直接获取每一个Entry对象,把Entry存储扫Set集合中去,再通过Entry对象获取键和值。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WH2fsP8e-1690457662733)(assets/1667309587178.png)]
/**
* 目标:掌握Map集合的第二种遍历方式:键值对。
*/
public class MapTest2 {
public static void main(String[] args) {
Map<String, 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集合
Set<Map.Entry<String, Double>> entries = map.entrySet();
for (Map.Entry<String, Double> entry : entries) {
String key = entry.getKey();
double value = entry.getValue();
System.out.println(key + "---->" + value);
}
}
}
2.5 Map集合遍历方式3
Map集合的第三种遍历方式,需要用到下面的一个方法forEach,而这个方法是JDK8版本以后才有的。调用起来非常简单,最好是结合的lambda表达式一起使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i25MR6Px-1690457662734)(assets/1667309230571.png)]
/**
* 目标:掌握Map集合的第二种遍历方式:键值对。
*/
public class MapTest3 {
public static void main(String[] args) {
Map<String, 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集合,传递匿名内部类
map.forEach(new BiConsumer<String, Double>() {
@Override
public void accept(String k, Double v) {
System.out.println(k + "---->" + v);
}
});
//遍历map集合,传递Lambda表达式
map.forEach(( k, v) -> {
System.out.println(k + "---->" + v);
});
}
}
2.6 Map集合案例
学习完Map集合的基本用法之后,接下来我们做一个综合案例,将Map集合运用一下。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-87YisJvC-1690457662737)(assets/1667311182716.png)]
先分析需求,再考虑怎么用代码实现
1.首先可以将80个学生选择的景点放到一个集合中去(也就是说,集合中的元素是80个任意的ABCD元素)
2.准备一个Map集合用来存储景点,以及景点被选择的次数
3.遍历80个学生选择景点的集合,得到每一个景点,判断Map集合中是否包含该景点
如果不包含,则存储"景点=1"
如果包含,则存获取该景点原先的值,再存储"景点=原来的值+1"; 此时新值会覆盖旧值
/**
* 目标:完成Map集合的案例:统计投票人数。
*/
public class MapDemo4 {
public static void main(String[] args) {
// 1、把80个学生选择的景点数据拿到程序中来。
List<String> 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 3
data.add(selects[index]);
}
System.out.println(data);
// 2、开始统计每个景点的投票人数
// 准备一个Map集合用于统计最终的结果
Map<String, 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 {
// 说明这个景点是第一次统计,存入"景点=1"
result.put(s, 1);
}
}
System.out.println(result);
}
}
三、Stream流(补充)
各位同学,接下来我们学习一个全新的知识,叫做Stream流(也叫Stream API)。它是从JDK8以后才有的一个新特性,是专业用于对集合或者数组进行便捷操作的。有多方便呢?我们用一个案例体验一下,然后再详细学习。
3.1 Stream流体验
案例需求:有一个List集合,元素有"张三丰","张无忌","周芷若","赵敏","张强"
,找出姓张,且是3个字的名字,存入到一个新集合中去。
List<String> names = new ArrayList<>();
Collections.addAll(names, "张三丰","张无忌","周芷若","赵敏","张强");
System.out.println(names);
- 用传统方式来做,代码是这样的
// 找出姓张,且是3个字的名字,存入到一个新集合中去。
List<String> list = new ArrayList<>();
for (String name : names) {
if(name.startsWith("张") && name.length() == 3){
list.add(name);
}
}
System.out.println(list);
- 用Stream流来做,代码是这样的(ps: 是不是想流水线一样,一句话就写完了)
List<String> list2 = names.stream().filter(s -> s.startsWith("张")).filter(a -> a.length()==3).collect(Collectors.toList());
System.out.println(list2);
先不用知道这里面每一句话是什么意思,具体每一句话的含义,待会再一步步学习。现在只是体验一下。
学习Stream流我们接下来,会按照下面的步骤来学习。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IjNJTwXy-1690457662739)(assets/1667649164429.png)]
3.2 Stream流的创建
好,接下来我们正式来学习Stream流。先来学习如何创建Stream流、或者叫获取Stream流。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4MyFrBop-1690457662740)(assets/1667649331568.png)]
主要掌握下面四点:
1、如何获取List集合的Stream流?
2、如何获取Set集合的Stream流?
3、如何获取Map集合的Stream流?
4、如何获取数组的Stream流?
直接上代码演示
/**
* 目标:掌握Stream流的创建。
*/
public class StreamTest2 {
public static void main(String[] args) {
// 1、如何获取List集合的Stream流?
List<String> names = new ArrayList<>();
Collections.addAll(names, "张三丰","张无忌","周芷若","赵敏","张强");
Stream<String> stream = names.stream();
// 2、如何获取Set集合的Stream流?
Set<String> set = new HashSet<>();
Collections.addAll(set, "刘德华","张曼玉","蜘蛛精","马德","德玛西亚");
Stream<String> stream1 = set.stream();
stream1.filter(s -> s.contains("德")).forEach(s -> System.out.println(s));
// 3、如何获取Map集合的Stream流?
Map<String, Double> map = new HashMap<>();
map.put("古力娜扎", 172.3);
map.put("迪丽热巴", 168.3);
map.put("马尔扎哈", 166.3);
map.put("卡尔扎巴", 168.3);
Set<String> keys = map.keySet();
Stream<String> ks = keys.stream();
Collection<Double> values = map.values();
Stream<Double> vs = values.stream();
Set<Map.Entry<String, Double>> entries = map.entrySet();
Stream<Map.Entry<String, Double>> kvs = entries.stream();
kvs.filter(e -> e.getKey().contains("巴"))
.forEach(e -> System.out.println(e.getKey()+ "-->" + e.getValue()));
// 4、如何获取数组的Stream流?
String[] names2 = {"张翠山", "东方不败", "唐大山", "独孤求败"};
Stream<String> s1 = Arrays.stream(names2);
Stream<String> s2 = Stream.of(names2);
}
}
3.3 Stream流中间方法
在上一节,我们学习了创建Stream流的方法。接下来我们再来学习,Stream流中间操作的方法。
中间方法指的是:调用完方法之后其结果是一个新的Stream流,于是可以继续调用方法,这样一来就可以支持链式编程(或者叫流式编程)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T1omtUAw-1690457662742)(assets/1667649379223.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HtciJk6U-1690457662744)(assets/1667649509262.png)]
话不多说,直接上代码演示
/**
* 目标:掌握Stream流提供的常见中间方法。
*/
public class StreamTest3 {
public static void main(String[] args) {
List<Double> 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));
List<Student> 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 s6
students.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);
// distinct去重复,自定义类型的对象(希望内容一样就认为重复,重写hashCode,equals)
students.stream().filter(s -> s.getHeight() > 168)
.distinct().forEach(System.out::println);
Stream<String> st1 = Stream.of("张三", "李四");
Stream<String> st2 = Stream.of("张三2", "李四2", "王五");
Stream<String> allSt = Stream.concat(st1, st2);
allSt.forEach(System.out::println);
}
}
3.5 Stream流终结方法
最后,我们再学习Stream流的终结方法。这些方法的特点是,调用完方法之后,其结果就不再是Stream流了,所以不支持链式编程。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qpUUJlCS-1690457662746)(assets/1667649788535.png)]
我列举了下面的几个终结方法,接下来用几个案例来一个一个给同学们演示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wxHiuZnz-1690457662748)(assets/1667649867150.png)]
话不多说,直接上代码
/**
* 目标:Stream流的终结方法
*/
public class StreamTest4 {
public static void main(String[] args) {
List<Student> 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的学生对象,并放到一个新集合中去返回。
// 流只能收集一次。
List<Student> students1 = students.stream().filter(a -> a.getHeight() > 170).collect(Collectors.toList());
System.out.println(students1);
Set<Student> students2 = students.stream().filter(a -> a.getHeight() > 170).collect(Collectors.toSet());
System.out.println(students2);
// 需求5:请找出身高超过170的学生对象,并把学生对象的名字和身高,存入到一个Map集合返回。
Map<String, 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));
}
}
到这里,关于Stream流的操常见操作我们就已经学习完了。当然Stream流还有一些其他的方法,同学们遇到了也可以自己再研究一下。