菜鸟之路Day11-12一一集合进阶(四)

简介: ### 菜鸟之路 Day11-12:集合进阶(四)作者:blue 时间:2025.1.29-1.30本文详细介绍了Java集合的高级用法,包括可变参数、Collections工具类、综合练习、不可变集合和Stream流。通过具体代码示例,讲解了可变参数的使用规则、Collections常用API、随机点名练习、不可变集合的创建方法以及Stream流的操作步骤。内容丰富实用,适合初学者深入理解Java集合框架。

菜鸟之路Day11-12一一集合进阶(四)

作者:blue

时间:2025.1.29-1.30

0.概述

内容学习自黑马程序员,BV1yW4y1Y7Ms,过年了,精神上有些懈怠,效率有所下降,得迅速调整一下。

1.可变参数

方法形参的个数是可以发生变化的,0 1 2 3 ……

格式:属性类型……名字

有关可变参数的小细节:

​ 1.在方法的形参中最多只能写一个可变参数

​ 2.在方法的形参当中,如果出现了可变参数以外,还有其他形参,那么可变参数要写在最后

例子:

public class Test {
   
    public static void main(String[] args) {
   
        System.out.println(getSum(1,1,2,3,4,5,5));
        System.out.println(getSum(1,2,3));
    }
    public static int getSum(int...args){
   
        //可变参数,本质是一个数组
        int sum=0;
        for(int i:args){
   
            sum+=i;
        }
        return sum;
    }
}

2.Collections

java.util.Collections:是集合工具类

作用:Collections不是集合,而是集合的工具类

Collections常用的API代码演示:

package Test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;

public class CollectionsTest {
   
    public static void main(String[] args) {
   
        //1.public static <T> boolean addAll(Collection<T> c,T... elements) 批量添加元素
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,1,2,3,4,5,6,7,8,9,10);
        System.out.println(list);

        System.out.println("================================");

        //2.public static void shuffle(List<?> list) 打乱List集合元素的顺序,注意,这个Set是不能用的
        Collections.shuffle(list);
        System.out.println(list);

        System.out.println("================================");

        //3.public static <T> void sort(List<T> list) 排序
        Collections.sort(list);
        System.out.println(list);

        System.out.println("================================");

        //4.public static <T> void sort(List<T> list,Comparator<T> c) 根据指定的规则进行排序
        Collections.sort(list, new Comparator<Integer>() {
   
            @Override
            public int compare(Integer o1, Integer o2) {
   
                return o2-o1;
            }
        });
        System.out.println(list);

        System.out.println("================================");

        //5.public static <T> int binarySearch(List<T> list,T key) 用二分查找法查找元素,注意二分查找List必须得是有序的
        Collections.sort(list);//先变成有序的
        int index = Collections.binarySearch(list,2);//查找2的位置
        System.out.println(index);//2的索引是1

        System.out.println("================================");

        //6.public static <T> int fill(List<T> list,T obj) 使用指定的元素填充集合
        //Collections.fill(list,3);
        //System.out.println(list);

        //7.public static <T> void max/min(Collection<T> coll) 根据默认的自然排序
        System.out.println(Collections.max(list));
        System.out.println("================================");

        //8.public static <T> void swap(List<?> list,int i,int j) 交换集合中指定位置的元素
        Collections.swap(list,1,8);
        System.out.println(list);
    }
}

3.综合练习

练习一:

随机点名,学生属性:姓名,年龄,性别

public class Test1 {
   
    public static void main(String[] args) {
   
        ArrayList<Student> list = new ArrayList<>();
        Student s1 = new Student("zhangsan",18,"男");
        Student s2 = new Student("lisi",21,"男");
        Student s3 = new Student("wangwu",18,"男");
        Student s4 = new Student("zhaoliu",16,"女");
        Student s5 = new Student("xiaoqi",18,"男");
        Student s6 = new Student("laoba",17,"女");
        Student s7 = new Student("huangjiu",18,"男");

        Collections.addAll(list,s1,s2,s3,s4,s5,s6,s7);

        Random rd = new Random();
        int index = rd.nextInt(list.size());

        System.out.println(list.get(index));
    }
}

练习2:

带概率的随机点名,要求有70%概率随机到男生,有30%的概率随机到女生

public class Test2 {
   
    public static void main(String[] args) {
   
        //创建一个集合,存储7个1,和3个0,1代表抽男生,0代表抽女生,这样就随机出了概率
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,1,1,1,1,1,1,1,0,0,0);
        Collections.shuffle(list);//打乱
        Random rd = new Random();
        int index = rd.nextInt(list.size());//随机抽取数字,产生概率0.7和0.3的过程
        int number = list.get(index);//1代表抽男生,0代表抽女生

        ArrayList<String> boyList = new ArrayList<>();
        Collections.addAll(boyList,"ggboy","zhangsan","kevin","james","zero","888","666");

        ArrayList<String> girlList = new ArrayList<>();
        Collections.addAll(girlList,"刘亦菲","章若楠","田曦微");

        if(number==1){
   
            int boyindex = rd.nextInt(boyList.size());
            System.out.println(boyList.get(boyindex));
        }
        else
        {
   
            int girlindex = rd.nextInt(girlList.size());
            System.out.println(girlList.get(girlindex));
        }
    }
}

练习3:

要求:被点到的学生不会再被点到,但是全部点完了,就得重开一把

public class Test3 {
   
    public static void main(String[] args) {
   
        ArrayList<String> list1 = new ArrayList<>();
        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list1,"ggboy","zhangsan","kevin","james","zero","888","666","刘亦菲","章若楠","田曦微");
        int cnt = list1.size();
        Random rd = new Random();

        for(int j=1;j<=10;j++){
   
            System.out.println("================="+j+"轮===================");
            for(int i=1;i<=cnt;i++){
   
                int index = rd.nextInt(list1.size());
                String res = list1.remove(index); //抽到它就把他删掉,保持,单轮次内的唯一性
                list2.add(res);
                System.out.println(res);
            }
            //做一个交替滚动
            list1.addAll(list2);
            list2.clear();
        }
    }
}

练习四:

需求:定义一个Map集合,键用省份名称province,值表示市city,但是市会有多个。添加完毕后,遍历结果格式如下:

​ 江苏省 = 南京市,扬州市,苏州市,无锡市,常州市

​ 湖北省 = 武汉市,孝感市,十堰市,宜昌市,鄂州市

​ 河北省 = 石家庄市,唐山市,邢台市,保定市,张家口市

public class Test4 {
   
    public static void main(String[] args) {
   
        HashMap<String, ArrayList<String>> mp = new HashMap<>();
        ArrayList<String> list1 = new ArrayList<>();
        Collections.addAll(list1,"南京市","扬州市","苏州市","无锡市","常州市");

        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"武汉市","孝感市","十堰市","宜昌市","鄂州市");

        ArrayList<String> list3 = new ArrayList<>();
        Collections.addAll(list3,"石家庄市","唐山市","邢台市","保定市","张家口市");

        mp.put("江苏省",list1);
        mp.put("湖北省",list2);
        mp.put("河北省",list3);

        mp.forEach(new BiConsumer<String, ArrayList<String>>() {
   
            @Override
            public void accept(String s, ArrayList<String> strings) {
   
                System.out.print(s+" "+"="+" ");
                for (int i = 0; i < strings.size(); i++) {
   
                    if(i!=strings.size()-1){
   
                        System.out.print(strings.get(i)+","+" ");
                    }
                    else System.out.print(strings.get(i));
                }
                System.out.println();
            }
        });
    }
}

4.不可变的集合

应用场景:1.如果某个数据不能被修改,把他防御性的拷贝到不可变集合中是个很好的实践

​ 2.当集合对象被不可信的库调用时,不可变形式是安全的。

​ 简单理解:不想让别人修改集合中的内容

创建不可变集合的书写格式

在List,Set,Map接口中,都存在静态的of方法,可以获取一个不可变的集合

注意:这个集合不能添加,不能删除,不能修改

public class Day11Test1 {
   
    public static void main(String[] args) {
   
        //static <E> List<E> of(E...elements) 创建一个具有指定元素的List集合对象
        List<Integer> list = List.of(1,2,3,4,5,6);
        /*
            list.add(1);
            list.remove(0);
            这时各种试图改变集合的操作都是不被允许的
        */

        //static <E> Set<E> of(E...elements) 创建一个具有指定元素的Set集合对象
        //Set<Integer> set = Set.of(1,1,2,3,4,5,6);注意集合元素是不可重复的,创建不可变集合,输入重复的内容,也是不被允许的
        Set<Integer> set = Set.of(1,2,3,4,5,6);

        //static <K,V> Map<K,V> of(E...elements) 创建一个具有指定元素的Map集合对象
        //注意:创建时,键不能重复
        //注意:最多只能添加10个键值对!!!
        Map<String,Integer> mp = Map.of("zhangsan",14,"lisi",15);

        //如果要添加元素的数量多余10个,可以用以下方法来解决,它的思想是将键与值视为整体,键值对为Map.Entry对象,这样子我们就只有一个可变参数,就可以不去限制长度
        //步骤:

        //1.创建一个普通的Map集合
        HashMap<String,String> hm = new HashMap<>();
        hm.put("zhangsan","nanjing");
        hm.put("wangwu","shantou");
        hm.put("xiaomu","qingdao");
        hm.put("chener","jiaxin");

        //2.利用上面的数据来创建一个不可变的集合

        /*
        //获取到所有键值对对象(Entry对象)
        Set<Map.Entry<String,String>> entries = hm.entrySet();
        //把entries变成一个数组
        Map.Entry[] arr = new Map.Entry[0];
        //toArray方法会在底层比较集合长度跟数组长度两者的大小
        //如果集合长度 > 数组长度 :数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
        //如果集合长度 <= 数组的长度 :数据在数组中放的下,此时不会创建新数组,而是直接用
        //所以那里的参数0,是最节约空间的方法
        Map.Entry[] arr2 = entries.toArray(arr);

        //这样就创建了一个不可变集合
        Map map = Map.ofEntries(arr2);
        */

        //以上方法麻烦,jdk10以后
        Map<String,String> map = Map.copyOf(hm);//这样创建出来就是一个不可变map,这样长度就不会被限定了
        //map.put("aaa","bbb"); Error
    }
}

5.Stream流

Stream流初体验:

public class StreamTest1 {
   
    public static void main(String[] args) {
   
        /*
           创建集合添加元素,完成以下需求:
           1.把所有“张”开头的元素存储到新集合中
           2.把"张"开头的,长度为3的元素再存储到新集合中
           3.遍历打印最终结果
        */
        ArrayList<String> list1 = new ArrayList<>();
        Collections.addAll(list1,"张无忌","周芷若","赵敏","赵强","张三丰");

        list1.stream().filter(name->name.startsWith("张")).filter(name -> name.length() == 3 ).forEach(System.out::println);
    }
}

Stream流的作用:结合了Lambda表达式,简化集合,数组的操作

Stream流的使用步骤:

先得到一条Stream流(流水线),并把数据放上去;

获取方式 方法名 说明
单列集合 default Stream stream() Collection中的默认方法
双列集合 无法直接使用stream流
数组 public static Stream stream(T[] array) Arrays工具类中的静态方法
一堆零散数据 public static Stream of(T...values) Stream接口中的静态方法

单列集合

public class StreamTest2 {
   
    public static void main(String[] args) {
   
        //1.单列集合获取Stream流
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","c","d","e","f");

        //Stream<String> stream1 = list.stream();获取到一条流水线

        //使用终结方法打印一下流水线上的所有数据
        list.stream().forEach(s -> System.out.println(s));
    }
}

双列集合

public class StreamTest3 {
   
    public static void main(String[] args) {
   
        //1.创建双列集合
        HashMap<String,Integer> hm = new HashMap<>();
        //2.添加数据
        hm.put("aaa",111);
        hm.put("bbb",222);
        hm.put("ccc",333);
        hm.put("ddd",444);

        //3.第一种获取stream流
        //用keySet方法获取它所有的键的单列集合
        hm.keySet().stream().forEach(s-> System.out.println(s));

        //4.第二种方法获取stream流
        //获取键值对集合,再获取其Stream流
        hm.entrySet().stream().forEach(s-> System.out.println(s));
    }
}

数组

public class StreamTest4 {
   
    public static void main(String[] args) {
   
        int[] arr = {
   1,2,3,4,5,6,7,8};

        //利用工具类Arrays中的方法获取Stream流
        Arrays.stream(arr).forEach(s -> System.out.println(s));
    }
}

一堆零散的数据

import java.util.stream.Stream;
public class StreamTest5 {
   
    public static void main(String[] args) {
   
        Stream.of(1,2,3,4,5).forEach(s -> System.out.println(s));
    }
}

//注意:
//Stream接口中静态方法of的细节
//方法的形参是一个可变参数,可以传递一堆零散数据,也可以传递数组
//但是数组必须是引用数据的,如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream当中

②使用中间方法对流水线上的数据进行操作;

注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程

注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据

public class StreamTest6 {
   
    public static void main(String[] args) {
   
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰","张翠山","张良","赵敏","谢逊");

        //1.filter 过滤 把张开头的留下,其余的数据过滤不要
        /*list.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                //如果返回值为true,表示当前的数据留下
                //如果返回值为false,表示当前数据舍弃不要
                return s.startsWith("张");
            }
        }).forEach(s -> System.out.println(s));*/

        list.stream().filter(s -> s.startsWith("张")).forEach(s -> System.out.print(s));

        System.out.println();
        System.out.println("==========================================");

        //2.limit 获取前几个元素
        list.stream().limit(3).forEach(s -> System.out.print(s));

        System.out.println();
        System.out.println("==========================================");

        //3.skip 跳过前几个元素
        list.stream().skip(4).forEach(s -> System.out.print(s));

        System.out.println();
        System.out.println("==========================================");

        //4.distinct 元素去重,依赖(hashCode和equals方法)
        list.add("张无忌");
        list.add("张无忌");
        list.stream().distinct().forEach(s-> System.out.print(s));

        System.out.println();
        System.out.println("==========================================");

        //5.concat 合并a,b两个流为一个流
        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"你好","你不好");
        Stream.concat(list.stream(),list2.stream()).forEach(s -> System.out.print(s));

        System.out.println();
        System.out.println("==========================================");

        //6.map 转换流中的数据类型
        ArrayList<String> list3 = new ArrayList<>();
        //后面的数字代表年龄
        Collections.addAll(list3,"小张-15","小赵-16","小风-17","小良-18","小王-19");

        //需求:只获取里面年龄并进行打印
        //String -> int

        /*list3.stream().map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s){
                String[] arr = s.split("-");
                String ageString = arr[1];
                int age = Integer.parseInt(ageString);
                return age;
            }
        }).forEach(s -> System.out.print(s+" "));*/

        list3.stream().map(s -> Integer.parseInt(s.split("-")[1])).forEach(s-> System.out.print(s+" "));

        System.out.println();
        System.out.println("==========================================");
    }
}

③使用终结方法对流水线上的数据进行操作

/*
    void forEach(Consumer action)    遍历
    long count()    统计
    toArray()    收集流中的数据,放到数组中
*/
public class StreamTest7 {
   
    public static void main(String[] args) {
   
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"aaa","bbb","ccc","ddd","eee","fff","ggg");

        System.out.println(list.stream().count());

        //toArray() 收集流中的数据,放到数组中
        //Object[] arr1 = list.stream().toArray();
        //System.out.println(Arrays.toString(arr1));

        //指定数组类型
        /*String[] arr = list.stream().toArray(new IntFunction<String[]>() {
            @Override
            public String[] apply(int value) {
                return new String[value];
            }
        });*/

        String[] arr = list.stream().toArray(value -> new String[value]);

        System.out.println(Arrays.toString(arr));
    }
}
目录
相关文章
|
25天前
|
供应链 监控 安全
对话|企业如何构建更完善的容器供应链安全防护体系
阿里云与企业共筑容器供应链安全
171357 14
|
28天前
|
供应链 监控 安全
对话|企业如何构建更完善的容器供应链安全防护体系
随着云计算和DevOps的兴起,容器技术和自动化在软件开发中扮演着愈发重要的角色,但也带来了新的安全挑战。阿里云针对这些挑战,组织了一场关于云上安全的深度访谈,邀请了内部专家穆寰、匡大虎和黄竹刚,深入探讨了容器安全与软件供应链安全的关系,分析了当前的安全隐患及应对策略,并介绍了阿里云提供的安全解决方案,包括容器镜像服务ACR、容器服务ACK、网格服务ASM等,旨在帮助企业构建涵盖整个软件开发生命周期的安全防护体系。通过加强基础设施安全性、技术创新以及倡导协同安全理念,阿里云致力于与客户共同建设更加安全可靠的软件供应链环境。
150300 32
|
1月前
|
弹性计算 人工智能 安全
对话 | ECS如何构筑企业上云的第一道安全防线
随着中小企业加速上云,数据泄露、网络攻击等安全威胁日益严重。阿里云推出深度访谈栏目,汇聚产品技术专家,探讨云上安全问题及应对策略。首期节目聚焦ECS安全性,提出三道防线:数据安全、网络安全和身份认证与权限管理,确保用户在云端的数据主权和业务稳定。此外,阿里云还推出了“ECS 99套餐”,以高性价比提供全面的安全保障,帮助中小企业安全上云。
201980 15
对话 | ECS如何构筑企业上云的第一道安全防线
|
2天前
|
Linux iOS开发 MacOS
deepseek部署的详细步骤和方法,基于Ollama获取顶级推理能力!
DeepSeek基于Ollama部署教程,助你免费获取顶级推理能力。首先访问ollama.com下载并安装适用于macOS、Linux或Windows的Ollama版本。运行Ollama后,在官网搜索“deepseek”,选择适合你电脑配置的模型大小(如1.5b、7b等)。通过终端命令(如ollama run deepseek-r1:1.5b)启动模型,等待下载完成即可开始使用。退出模型时输入/bye。详细步骤如下图所示,轻松打造你的最强大脑。
1158 68
|
9天前
|
机器学习/深度学习 自然语言处理
Deepseek开源R1系列模型,纯RL助力推理能力大跃升!
近期Deepseek正式发布 DeepSeek-R1,并同步开源模型权重。DeepSeek-R1 遵循 MIT License,允许用户通过蒸馏技术借助 R1 训练其他模型。
|
5天前
|
人工智能 JavaScript 前端开发
白嫖 DeepSeek ,低代码竟然会一键作诗?
宜搭低代码平台接入 DeepSeek AI 大模型能力竟然这么方便!本教程将揭秘宜搭如何快速接入 DeepSeek API,3 步打造专属作诗机器人,也许你还能开发出更多有意思的智能玩法,让创意在代码间自由生长。
633 11
|
3天前
|
Linux iOS开发 MacOS
DeepSeek爆火,如何免费部署到你的电脑上?获取顶级推理能力教程来了
如何在本地电脑上免费部署DeepSeek,获取顶级推理能力?只需三步:1. 访问Ollama官网下载并安装对应操作系统的版本(支持macOS、Linux和Windows)。2. 打开Ollama并确保其正常运行。3. 在Ollama官网搜索并选择DeepSeek模型(如deepseek-r1),根据电脑配置选择合适的模型大小(1.5B至671B)。通过终端命令(如ollama run deepseek-r1:1.5b)运行模型,即可开始使用DeepSeek进行推理。退出模型时,在终端输入/bye。更多详情请参考Ollama官方文档。
|
13天前
|
机器学习/深度学习 自然语言处理 PyTorch
深入剖析Transformer架构中的多头注意力机制
多头注意力机制(Multi-Head Attention)是Transformer模型中的核心组件,通过并行运行多个独立的注意力机制,捕捉输入序列中不同子空间的语义关联。每个“头”独立处理Query、Key和Value矩阵,经过缩放点积注意力运算后,所有头的输出被拼接并通过线性层融合,最终生成更全面的表示。多头注意力不仅增强了模型对复杂依赖关系的理解,还在自然语言处理任务如机器翻译和阅读理解中表现出色。通过多头自注意力机制,模型在同一序列内部进行多角度的注意力计算,进一步提升了表达能力和泛化性能。
|
18天前
|
存储 人工智能 安全
对话|无影如何助力企业构建办公安全防护体系
阿里云无影助力企业构建办公安全防护体系
1262 11
|
4天前
|
机器学习/深度学习 搜索推荐 PyTorch
基于昇腾用PyTorch实现传统CTR模型WideDeep网络
本文介绍了如何在昇腾平台上使用PyTorch实现经典的WideDeep网络模型,以处理推荐系统中的点击率(CTR)预测问题。
149 65