菜鸟之路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));
    }
}
目录
相关文章
|
数据采集 算法 数据可视化
数据分析入门系列教程-决策树实战
数据分析入门系列教程-决策树实战
275 0
|
机器学习/深度学习 算法 数据可视化
利用SVM(支持向量机)分类算法对鸢尾花数据集进行分类
本文介绍了如何使用支持向量机(SVM)算法对鸢尾花数据集进行分类。作者通过Python的sklearn库加载数据,并利用pandas、matplotlib等工具进行数据分析和可视化。
1172 70
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
525 23
|
缓存 Java 数据库连接
Spring Boot奇迹时刻:@PostConstruct注解如何成为应用初始化的关键先生?
【8月更文挑战第29天】作为一名Java开发工程师,我一直对Spring Boot的便捷性和灵活性着迷。本文将深入探讨@PostConstruct注解在Spring Boot中的应用场景,展示其在资源加载、数据初始化及第三方库初始化等方面的作用。
473 0
|
人机交互 语音技术 vr&ar
汽车品牌选择使用VR虚拟现实技术展示汽车
虚拟现实汽车展厅利用VR技术,为客户提供生动、便捷的在线购车体验。用户通过佩戴VR设备,可在虚拟环境中全方位观察汽车外观、内饰,了解功能并定制颜色和配置。此外,还可与虚拟工作人员互动,获取更多信息和建议。该展厅不仅节省了客户的时间和精力,也为经销商降低了展示成本,提升了销售效率。未来,随着VR技术的进步,展厅将更加智能和普及,进一步融合线上线下购车流程,提供更丰富的互动体验。
415 12
|
SQL 数据安全/隐私保护 索引
SQL语句速成
《SQL语句速成》由blue编写,涵盖建表、插入、查询、更新、删除、视图创建、权限管理及索引操作等核心内容。通过具体示例介绍SQL基本语法和常用聚合函数,帮助读者快速掌握SQL编程技巧。发布于2024年7月19日。
266 7
|
传感器 机器学习/深度学习 人工智能
AI在自动驾驶汽车中的应用与未来展望
AI在自动驾驶汽车中的应用与未来展望
889 9
|
Java 程序员
菜鸟之路Day22一一反射与动态代理
本文介绍了Java反射机制和动态代理的基本概念及应用。反射允许编程访问类的成员变量、构造方法和成员方法,通过三种方式获取Class对象,并演示了如何使用反射创建对象、调用方法和修改字段值。动态代理则通过接口实现无侵入式功能增强,展示了如何利用`Proxy`类和`InvocationHandler`接口生成代理对象并拦截方法调用。结合实例代码,详细讲解了反射在实际开发中的应用场景,如保存对象信息到文件和根据配置文件动态创建对象。 反射的主要作用包括: 1. 获取类的所有信息。 2. 结合配置文件动态创建对象。 动态代理的核心优势在于能够在不修改原有代码的情况下,为对象添加额外功能。
217 0
|
人工智能 自然语言处理 机器人
对话阿里云CIO蒋林泉:AI时代,企业如何做好智能化系统建设?
对话阿里云CIO蒋林泉:AI时代,企业如何做好智能化系统建设?

热门文章

最新文章