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

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

作者:blue

时间:2025.1.29-1.30

文章目录

0.概述

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

1.可变参数

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

格式:属性类型......名字

有关可变参数的小细节:

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

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

例子:

java 复制代码
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代码演示:

java 复制代码
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.综合练习

练习一:

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

java 复制代码
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%的概率随机到女生

java 复制代码
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:

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

java 复制代码
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,但是市会有多个。添加完毕后,遍历结果格式如下:

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

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

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

java 复制代码
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方法,可以获取一个不可变的集合

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

java 复制代码
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流初体验:

java 复制代码
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接口中的静态方法

单列集合

java 复制代码
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));
    }
}

双列集合

java 复制代码
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));
    }
}

数组

java 复制代码
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));
    }
}

一堆零散的数据

java 复制代码
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流中的数据,不会影响原来集合或者数组中的数据

java 复制代码
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("==========================================");
    }
}

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

java 复制代码
/*
	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));
    }
}
相关推荐
cccc楚染rrrr5 分钟前
572. 另一棵树的子树
java·数据结构·算法
精神病不行计算机不上班16 分钟前
[Java]泛型(二)泛型方法
java·python·算法
zm36 分钟前
C基础寒假练习(4)
java·前端·数据库
hamster20211 小时前
力扣【501. 二叉搜索树中的众数】Java题解
java·算法·leetcode
落幕1 小时前
C语言-运算符
java·开发语言
就很对1 小时前
6.进程的使用方式
java·linux·jvm
biubiubiu07061 小时前
使用Redis生成全局唯一ID示例
java·数据库·redis
萌新小码农‍2 小时前
回顾Maven
java·maven
潜水阿宝2 小时前
微服务网关鉴权之sa-token
java·spring boot·微服务·gateway·springcloud