Java学习路线(进阶篇二)


前言

主要是记录学习Java时的笔记,这篇学习的是的常用API、正则表达式、Lambda、算法和集合(Collection、数据结构、LIst、泛型深入、Set、Collection、Map、集合嵌套、不可变集合、Stream、异常


提示:以下是本篇文章正文内容

一、常用API

什么是API?:应用程序编程接口(就是Java帮我们写好的一些方法,我们直接拿过来用就可以了)


1.Object(祖宗类)

父类toString()方法存在的意义是为了被子类重写,以便返回对象的内容信息,而不是地址信息!!
父类equals()方法存在的意义就是为了被子类重写,以便子类自己来定制比较规制(如比较两个子类对象的内容是否相同)!!,如果比较两个对象的地址可以用“==”代替
在这里插入图片描述

代码实例如下

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", sex=" + sex +
                ", age=" + age +
                '}';
    }
}


public class Test2 {
    public static void main(String[] args) {
        Student s1 = new Student("周雄", '男', 19);
        Student s2 = new Student("周雄", '男', 19);
        // equals默认是比较2个对象的地址是否相同,子类重写后会调用子类重写的来比较内容是否相同。
        System.out.println(s1.equals(s2));
        System.out.println(s1 == s2);
        System.out.println(Objects.equals(s1, s2));
    }
}


//        比较者:s1 == this
//        被比较者: s2 ==> o
 @Override
    public boolean equals(Object o){
        // 1、判断o是不是学生类型
        if(o instanceof Student){
            Student s2 = (Student) o;
            // 2、判断2个对象的内容是否一样。
//            if(this.name.equals(s2.name) &&
//                 this.age == s2.age && this.sex == s2.sex){
//                return true;
//            }else {
//                return false;
//            }
            return this.name.equals(s2.name) && this.age == s2.age&& this.sex == s2.sex ;

        }else {
            // 学生只能和学生比较,否则结果一定是false
            return false;
        }
    }
//        比较者:s1 == this
//        被比较者: s2 ==> o
    @Override//改进版--IDEA自动生成的代码
    public boolean equals(Object o) {
        // 1、判断是否是同一个对象比较,如果是返回true。
        if (this == o) return true;
        // 2、如果o是null返回false  如果o不是学生类型返回false  ...Student !=  ..Pig
        if (o == null || this.getClass() != o.getClass()) return false;
        // 3、说明o一定是学生类型而且不为null
        Student student = (Student) o;
        return sex == student.sex && age == student.age && Objects.equals(name, student.name);
    }


2.Objects(工具类-提供一些方法完成一些功能)

官方在进行字符串比较时,没有用字符串对象的equals方法,而是选择equals方法来比较(更安全-内部会进行非空校验)
在这里插入图片描述

实例代码

public class Test {
    public static void main(String[] args) {
        String s1 = null;
        String s2 = new String("itheima");
        // System.out.println(s1.equals(s2));   // 留下了隐患,可能出现空指针异常。
        System.out.println(Objects.equals(s1, s2)); // 更安全,结果也是对的!

        /**
             Objects:
             public static boolean equals(Object a, Object b) {
                     return (a == b) || (a != null && a.equals(b));
             }
         */

        System.out.println(Objects.isNull(s1)); // true
        System.out.println(s1 == null); // true

        System.out.println(Objects.isNull(s2)); // false
        System.out.println(s2 == null); // false

    }
}


3.StringBuilder(不可变的字符串类)

可以把它看成是一个对象容器,提高字符串的操作效率,如拼接、修改等
在这里插入图片描述
注意:StringBuilder只是拼接字符串的手段,效率好(支持追加,反转,链式编程),最终的目的还是要恢复成String类型

实例代码

public class StringBuilderDemo1 {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder(); // ""
        sb.append("a");
        sb.append(1);
        sb.append(false);
        sb.append(3.3);
        sb.append("abc");
        System.out.println(sb);
        StringBuilder sb1 = new StringBuilder();
        // 支持链式编程
        sb1.append("a").append("b").append("c").append("我爱你中国");
        System.out.println(sb1);
        // 反转
        sb1.reverse().append("110");
        System.out.println(sb1);
        System.out.println(sb1.length());
        // 注意:StringBuilder只是拼接字符串的手段:效率好。
        // 最终的目的还是要恢复成String类型。
        StringBuilder sb2 = new StringBuilder();
        sb2.append("123").append("456");
        // 恢复成String类型
        String rs = sb2.toString();
        check(rs);
    }

    public static void check(String data){
        System.out.println(data);
    }
}

定义字符串使用String,拼接、修改等操作字符串使用StringBuilder

String类拼接字符串原理图-String内容时不可变的,拼接字符串性能差

在这里插入图片描述

StringBuilder提高效率原理图-内容时可变的,拼接字符串性能好,代码优雅

在这里插入图片描述

在这里插入图片描述

案例-打印数组内容


public class StringBuilderTest2 {
    public static void main(String[] args) {
        int[] arr1 = null;
        System.out.println(toString(arr1));
        int[] arr2 = {10, 88, 99};
        System.out.println(toString(arr2));
        int[] arr3 = {};
        System.out.println(toString(arr3));
    }
    /**
       1、定义方法接收任意整型数组,返回数组内容格式
     */
    public static String toString(int[] arr){
       if(arr != null){
            // 2、开始拼接内容。
           StringBuilder sb = new StringBuilder("[");
           for (int i = 0; i < arr.length; i++) {
               sb.append(arr[i] ).append(i == arr.length - 1 ? "" : ", ");
           }
           sb.append("]");
           return sb.toString();//最后转换回字符串
       }else {
           return null;
       }
    }
}

//输出结果
//null
//[10,88,99]
//[]

4.Math(基本数字运算的方法)

Math类(工具类)没有提供公开的构造器,如果类中的成员是静态的话,可以用类名直接调用
在这里插入图片描述

实例代码

 System.out.println(Math.random());  // 0.0 - 1.0 (包前不包后)

        // 拓展: 3 - 9 之间的随机数  (0 - 6) + 3
        //  [0 - 6] + 3
        int data =  (int)(Math.random() * 7) + 3;
        System.out.println(data);

5.System(工具类)

代表了当前系统,提供了一些与系统相关的方法

在这里插入图片描述

实例代码

public class SystemDemo {
    public static void main(String[] args) {
        System.out.println("程序开始。。。");

        // System.exit(0); // JVM终止!

        // 2、计算机认为时间有起源:返回1970-1-1 00:00:00 走到此刻的总的毫秒值:时间毫秒值。
        long time = System.currentTimeMillis();
        System.out.println(time);

        long startTime = System.currentTimeMillis();
        // 进行时间的计算:性能分析
        for (int i = 0; i < 100000; i++) {
            System.out.println("输出:" + i);
        }
        long endTime = System.currentTimeMillis();
        System.out.println((endTime - startTime)/1000.0 + "s");
        // 3、做数组拷贝(了解)
        /**
         arraycopy(Object src,  int  srcPos,
         Object dest, int destPos,
         int length)
         参数一:被拷贝的数组
         参数二:从哪个索引位置开始拷贝
         参数三:复制的目标数组
         参数四:粘贴位置
         参数五:拷贝元素的个数
         */
        int[] arr1 = {10, 20, 30, 40, 50, 60, 70};
        int[] arr2 = new int[6]; // [0, 0, 0, 0, 0, 0] ==>  [0, 0, 40, 50, 60, 0]
        System.arraycopy(arr1, 3, arr2, 2, 3);
        System.out.println(Arrays.toString(arr2));
        System.out.println("-------------------");
        double i = 10.0;
        double j = 3.0;
//        System.out.println(k1);
        System.out.println("程序结束。。。。");
    }
}




6.BigDecimal(用于解决浮点型运算精度失真的问题)

在这里插入图片描述

实例代码

public class BigDecimalDemo {
    public static void main(String[] args) {
        // 浮点型运算的时候直接+  * / 可能会出现数据失真(精度问题)。
        System.out.println(0.09 + 0.01);
        System.out.println(1.0 - 0.32);
        System.out.println(1.015 * 100);
        System.out.println(1.301 / 100);

        System.out.println("-------------------------");
        double a = 0.1;
        double b = 0.2;
        double c = a + b;
        System.out.println(c);
        System.out.println("--------------------------");
        // 包装浮点型数据成为大数据对象 BigDeciaml
        BigDecimal a1 = BigDecimal.valueOf(a);
        BigDecimal b1 = BigDecimal.valueOf(b);
        BigDecimal c1 = a1.add(b1);
        // BigDecimal c1 = a1.subtract(b1);
        // BigDecimal c1 = a1.multiply(b1);
        // BigDecimal c1 = a1.divide(b1);
        System.out.println(c1);

        // 目的:double
        double rs = c1.doubleValue();
        System.out.println(rs);

        // 注意事项:BigDecimal是一定要精度运算的
        BigDecimal a11 = BigDecimal.valueOf(10.0);//获取BigDecimal对象
        BigDecimal b11 = BigDecimal.valueOf(3.0);
        /**
           参数一:除数 参数二:保留小数位数  参数三:四舍五入模式(其它还有进一法、去尾法)
         */
        BigDecimal c11 = a11.divide(b11, 2, RoundingMode.HALF_UP); // 3.3333333333
        System.out.println(c11);
        System.out.println("-------------------");
    }
}



7.Date

Date类代表当前所在系统的日期时间信息
在这里插入图片描述

案例–请计算出当前时间往后走1小时121秒之后的时间是多少(获取时间毫秒值,然后恢复成日期对象)

    public static void main(String[] args) {
   
        // 1、得到当前时间
        Date d1 = new Date();
        System.out.println(d1);

        // 2、当前时间往后走 1小时  121s
        long time2 = System.currentTimeMillis();
        time2 += (60 * 60 + 121) * 1000;

        // 3、把时间毫秒值转换成对应的日期对象。
        // Date d2 = new Date(time2);
        // System.out.println(d2);

        Date d3 = new Date();
        d3.setTime(time2);
        System.out.println(d3);

    }


8.SimpleDateFormat

可以完成日期时间的格式化操作
在这里插入图片描述
在这里插入图片描述

实例代码—格式化标准的时间形式

 public static void main(String[] args) {
        // 1、日期对象
        Date d = new Date();
        System.out.println(d);

        // 2、格式化这个日期对象 (指定最终格式化的形式)
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
        // 3、开始格式化日期对象成为喜欢的字符串形式
        String rs = sdf.format(d);
        System.out.println(rs);

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

        // 4、格式化时间毫秒值
        // 需求:请问121秒后的时间是多少
        long time1 = System.currentTimeMillis() + 121 * 1000;
        String rs2 = sdf.format(time1);
        System.out.println(rs2);

    }

案例

在这里插入图片描述

示例代码----解析时间

public class SimpleDateFormatDemo2 {
    public static void main(String[] args) throws ParseException {
        // 目标: 学会使用SimpleDateFormat解析字符串时间成为日期对象。
        // 有一个时间 2021年08月06日 11:11:11 往后 2天 14小时 49分 06秒后的时间是多少。
        // 1、把字符串时间拿到程序中来
        String dateStr = "2021年08月06日 11:11:11";

        // 2、把字符串时间解析成日期对象(本节的重点):形式必须与被解析时间的形式完全一样,否则运行时解析报错!
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        Date d = sdf.parse(dateStr);

        // 3、往后走2天 14小时 49分 06秒
        long time = d.getTime() + (2L*24*60*60 + 14*60*60 + 49*60 + 6) * 1000;//要加L防止数据越界

        // 4、格式化这个时间毫秒值就是结果
        System.out.println(sdf.format(time));
    }
}


案例—秒杀活动

在这里插入图片描述

实例代码

 public static void main(String[] args) throws ParseException {
        // 1、开始 和 结束时间
        String startTime = "2021-11-11 00:00:00";
        String endTime = "2021-11-11 00:10:00";

        // 2、小贾 小皮
        String xiaoJia =  "2021-11-11 00:03:47";
        String xiaoPi =  "2021-11-11 00:10:11";

        // 3、解析他们的时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d1 = sdf.parse(startTime);
        Date d2 = sdf.parse(endTime);
        Date d3 = sdf.parse(xiaoJia);
        Date d4 = sdf.parse(xiaoPi);

        if(d3.after(d1) && d3.before(d2)){
            System.out.println("小贾秒杀成功,可以发货了!");
        }else {
            System.out.println("小贾秒杀失败!");
        }

        if(d4.after(d1) && d4.before(d2)){
            System.out.println("小皮秒杀成功,可以发货了!");
        }else {
            System.out.println("小皮秒杀失败!");
        }
    }



9.Calendar

Calendar代表了系统此刻日期对应的日历对象,它是一个抽象类不能创建对象
在这里插入图片描述
在这里插入图片描述
calendar是可变日期对象,一旦修改后其对象本身表示的时间将产生变化

实例代码

  public static void main(String[] args) {
        // 1、拿到系统此刻日历对象
        Calendar cal = Calendar.getInstance();
        System.out.println(cal);

        // 2、获取日历的信息:public int get(int field):取日期中的某个字段信息。
        int year = cal.get(Calendar.YEAR);
        System.out.println(year);

        int mm = cal.get(Calendar.MONTH) + 1;
        System.out.println(mm);

        int days = cal.get(Calendar.DAY_OF_YEAR) ;
        System.out.println(days);

        // 3、public void set(int field,int value):修改日历的某个字段信息。
        // cal.set(Calendar.HOUR , 12);
        // System.out.println(cal);

        // 4.public void add(int field,int amount):为某个字段增加/减少指定的值
        // 请问64天后是什么时间
        cal.add(Calendar.DAY_OF_YEAR , 64);
        cal.add(Calendar.MINUTE , 59);

        //  5.public final Date getTime(): 拿到此刻日期对象。
        Date d = cal.getTime();
        System.out.println(d);

        //  6.public long getTimeInMillis(): 拿到此刻时间毫秒值
        long time = cal.getTimeInMillis();
        System.out.println(time);

在这里插入图片描述


10.包装类

就是8种基本数据类型对应的引用类型
在这里插入图片描述
Java为了实现一切皆对象,为8种基本类型提供了对应的引用类型]
集合和泛型只能支持包装类型,而不支持基本数据类型

自动装箱:基本类型的数据和变量可以直接赋值给包装类型的变量。

自动拆箱:包装类型的变量可以直接赋值给基本数据类型的变量

包装类特有的功能:
1、包装类的变量默认值可以是null,容错率更高。
2、可以把基本数据类型转换成字符串类型。
3、可以把字符串类型的数值转换成真实的数据类型


 String number = "23";
        //转换成整数
        // int age = Integer.parseInt(number);
        int age = Integer.valueOf(number);
        System.out.println(age + 1);

        String number1 = "99.9";
        //转换成小数
//        double score = Double.parseDouble(number1);
        double score = Double.valueOf(number1);
        System.out.println(score + 0.1);
        

二、正则表达式、Arrays类、Lambda表达式


1、正则表达式

正则表达式可以用一些规定的字符来制定规制,并用来检验数据格式的合法性

案例

在这里插入图片描述

示例代码


 public static void main(String[] args) {
        // 需求:校验qq号码,必须全部数字 6 - 20位
        System.out.println(checkQQ("251425998"));//true
        System.out.println(checkQQ("2514259a98"));//false
        System.out.println(checkQQ(null));//false
        System.out.println(checkQQ("2344"));//false

        System.out.println("-------------------------");
        // 正则表达式的初体验:
        System.out.println(checkQQ2("251425998"));
        System.out.println(checkQQ2("2514259a98"));
        System.out.println(checkQQ2(null));
        System.out.println(checkQQ2("2344"));

    }
	//正则表达式判断
    public static boolean checkQQ2(String qq){
    						//\d代表都是数字,\转译字符,
        return qq != null && qq.matches("\\d{6,20}");
    }


	
    public static boolean checkQQ(String qq){
        // 1、判断qq号码的长度是否满足要求
        if(qq == null || qq.length() < 6 || qq.length() > 20 ) {
            return false;
        }

        // 2、判断qq中是否全部是数字,不是返回false
        //  251425a87
        for (int i = 0; i < qq.length(); i++) {
            // 获取每位字符
            char ch = qq.charAt(i);
            // 判断这个字符是否不是数字,不是数字直接返回false
            if(ch < '0' || ch > '9') {
                return false;
            }
        }

        return true; // 肯定合法了!
    }




正则表达式的匹配规则字符串对象提供了匹配正则表达式规则的API

在这里插入图片描述

示例代码

 // 校验密码
        // 必须是数字 字母 下划线 至少 6位
        System.out.println("2442fsfsf".matches("\\w{6,}"));//true
        System.out.println("244f".matches("\\w{6,}"));//false

        // 验证码 必须是数字和字符  必须是4位
        System.out.println("23dF".matches("[a-zA-Z0-9]{4}"));//true
        System.out.println("23_F".matches("[a-zA-Z0-9]{4}"));//false
        System.out.println("23dF".matches("[\\w&&[^_]]{4}"));//true
        System.out.println("23_F".matches("[\\w&&[^_]]{4}"));//false



案例

在这里插入图片描述

示例代码

  public static void main(String[] args) {
        // 目标:校验 手机号码 邮箱  电话号码
        // checkPhone();
        // checkEmail();
        // checkTel();

        // 同学可以完成校验金额是否格式金额: 99  0.5  99.5  019   | 0.3.3

        int[] arr = {10, 4, 5,3, 4,6,  2};
        System.out.println(Arrays.binarySearch(arr, 2));

    }

    public static void checkTel(){
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请您输入您的电话号码:");
            String tel = sc.next();
            // 判断邮箱格式是否正确   027-3572457  0273572457
            if(tel.matches("0\\d{2,6}-?\\d{5,20}")){
                System.out.println("格式正确,注册完成!");
                break;
            }else {
                System.out.println("格式有误!");
            }
        }
    }

    public static void checkEmail(){
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请您输入您的注册邮箱:");
            String email = sc.next();
            // 判断邮箱格式是否正确   3268847878@qq.com
            // 判断邮箱格式是否正确   3268847dsda878@163.com
            // 判断邮箱格式是否正确   3268847dsda878@pci.com.cn
            if(email.matches("\\w{1,30}@[a-zA-Z0-9]{2,20}(\\.[a-zA-Z0-9]{2,20}){1,2}")){
                System.out.println("邮箱格式正确,注册完成!");
                break;
            }else {
                System.out.println("格式有误!");
            }
        }
    }

    public static void checkPhone(){
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请您输入您的注册手机号码:");
            String phone = sc.next();
            // 判断手机号码的格式是否正确
            if(phone.matches("1[3-9]\\d{9}")){
                System.out.println("手机号码格式正确,注册完成!");
                break;
            }else {
                System.out.println("格式有误!");
            }
        }
    }


正则表达式在字符串方法中的使用

在这里插入图片描述

示例代码


 public static void main(String[] args) {
        String names = "小路dhdfhdf342蓉儿43fdffdfbjdfaf小何";

        String[] arrs = names.split("\\w+");//从字符数字下划线开始分割
        for (int i = 0; i < arrs.length; i++) {
            System.out.println(arrs[i]);//小路-蓉儿-小何
        }

        String names2 = names.replaceAll("\\w+", "  ");//小路  蓉儿  小何
        System.out.println(names2);
    }



正则表达式支持爬取信息


public static void main(String[] args) {
        String rs = "跟黑马程序学习Java,电话020-43422424,或者联系邮箱" +
                "itcast@itcast.cn,电话18762832633,0203232323" +
                "邮箱bozai@itcast.cn,400-100-3233 ,4001003232";

        // 需求:从上面的内容中爬取出 电话号码和邮箱。
        // 1、定义爬取规则,字符串形式
        String regex = "(\\w{1,30}@[a-zA-Z0-9]{2,20}(\\.[a-zA-Z0-9]{2,20}){1,2})|(1[3-9]\\d{9})" +
                "|(0\\d{2,6}-?\\d{5,20})|(400-?\\d{3,9}-?\\d{3,9})";

        // 2、把这个爬取规则编译成匹配对象。
        Pattern pattern = Pattern.compile(regex);

        // 3、得到一个内容匹配器对象
        Matcher matcher = pattern.matcher(rs);

        // 4、开始找了
        while (matcher.find()) {
            String rs1 = matcher.group();//每找到一组取一组
            System.out.println(rs1);
        }

    }



2.Arrays类

数组操作工具类,专门用于操作数组元素的。
在这里插入图片描述

示例代码


 @Override//需重写toString(),不然返回的是地址
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }



  Student[] students = new Student[3];
        students[0] = new Student("吴磊",23 , 175.5);
        students[1] = new Student("谢鑫",18 , 185.5);
        students[2] = new Student("王亮",20 , 195.5);
        System.out.println(Arrays.toString(students));

        // Arrays.sort(students);  // 直接运行奔溃
          /**
           参数一:被排序的数组 必须是引用类型的元素
           参数二:匿名内部类对象,代表了一个比较器对象。
         */
         		//Lambda简化形式
Arrays.sort(students,(Student  o1,Student  o2)->{return Double.compare(o2.getHeight(),   o1.getHeight()); });
/
        Arrays.sort(students, new Comparator<Student>() {
		 @Override
            public int compare(Student o1, Student o2) {
                // 自己指定比较规则
                // return o1.getAge() - o2.getAge(); // 按照年龄升序排序!
                // return o2.getAge() - o1.getAge(); // 按照年龄降序排序!!
                // return Double.compare(o1.getHeight(), o2.getHeight()); // 比较浮点型可以这样写 升序
                return Double.compare(o2.getHeight(), o1.getHeight()); // 比较浮点型可以这样写  降序
            }
        });
        System.out.println(Arrays.toString(students));
        

3.Lambda表达式

Lambda表达式是JDK8开始后的一种新语法形式
主要是简化匿名内部类的代码写法(只能简化函数式接口的匿名内部类的写法形式)
在这里插入图片描述
函数式接口:必须是接口,其次接口中有且仅有一个抽象方法的形式
在这里插入图片描述

示例代码–简化过程


public class LambdaDemo2 {
    public static void main(String[] args) {
        // 目标:学会使用Lambda的标准格式简化匿名内部类的代码形式
        // 注意:Lambda只能简化接口中只有一个抽象方法的匿名内部类形式(函数式接口)
//        Swimming s1 = new Swimming() {
//            @Override
//            public void swim() {
//                System.out.println("老师游泳贼溜~~~~~");
//            }
//        };

//        Swimming s1 = () -> {
//            System.out.println("老师游泳贼溜~~~~~");
//        };

        Swimming s1 = () -> System.out.println("老师游泳贼溜~~~~~");
        go(s1);

        System.out.println("---------------------");
//        go(new Swimming() {
//            @Override
//            public void swim() {
//                System.out.println("学生游泳很开心~~~");
//            }
//        });

//        go(() ->{
//                System.out.println("学生游泳很开心~~~");
//        });

        go(() -> System.out.println("学生游泳很开心~~~"));


    }

    public static void go(Swimming s){
        System.out.println("开始。。。");
        s.swim();
        System.out.println("结束。。。");
    }
}

	@FunctionalInterface // 一旦加上这个注解必须是函数式接口,里面只能有一个抽象方法
	interface Swimming{
	    void swim();
	}



Lambda表达式的省略写法

1、参数类型可以省略不写,如果只有一个参数,同时()也可以省略不写
2、如果方法体代码只有一行代码,可以省略大括号不写,同时省略分号如果这行代码是return语句,必须省略return不写,同时也必须省略“;”不写。

示例代码


	 Arrays.sort(ages1, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1; //  降序
            }
        });
        //Lambda简化
    	Arrays.sort(ages1, (Integer o1, Integer o2) -> {
                return o2 - o1; //  降序
        });
        Arrays.sort(ages1, ( o1,  o2) -> {
            return o2 - o1; //  降序
        });
			//return不写,分号不写
        Arrays.sort(ages1, ( o1,  o2 ) ->  o2 - o1 );




    	btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("有人点我,点我,点我!!");
            }
        });
        //Lambda简化
    	 btn.addActionListener((ActionEvent e) -> {
                System.out.println("有人点我,点我,点我!!");
        });
			//一个参数的话,参数类型可以不写
        btn.addActionListener(( e) -> {
            System.out.println("有人点我,点我,点我!!");
        });
			//一个参数的话,()可以不写
        btn.addActionListener( e -> {
            System.out.println("有人点我,点我,点我!!");
        });
				//大括号不写,分号不写
        btn.addActionListener( e -> System.out.println("有人点我,点我,点我!!") );



三、集合

集合的类型不固定,大小是可变的,并且只能储存引用类型的数据.集合适合做数据个数不确定,且要做增删元素的场景
集合都是支持泛型的,可以在编译阶段约束集合只能操作某种数据类型(JDK1.7开始后面的泛型类型声明可以省略不写)

集合和泛型都只能支持引用数据类型,不支持基本数据类型,所以集合中存储的元素都认为是对象


1.Collection(单列集合的祖宗接口)

每个元素只包含一个值,它的功能是全部单列集合都可以继承使用的
在这里插入图片描述

集合的遍历方式

1、迭代器(Iterator):默认指向当前集合的索引0,如果取元素越界会出现NoSuchElenmentException异常

2、foreach(增强for循环JDK5之后)既可以遍历集合也可以遍历数组

示例代码


    public static void main(String[] args) {
        Collection<String> lists = new ArrayList<>();
        lists.add("赵敏");
        lists.add("小昭");
        lists.add("殷素素");
        lists.add("周芷若");
        System.out.println(lists);
        // [赵敏, 小昭, 殷素素, 周芷若]
        //  ele

        for (String ele : lists) {
            System.out.println(ele);
        }

        System.out.println("------------------");
        double[] scores = {100, 99.5 , 59.5};
        for (double score : scores) {
            System.out.println(score);
//            if(score == 59.5){//修改第三方变量的值不会影响到集合中的值
//                score = 100.0; // 修改无意义,不会影响数组的元素值。
//            }
        }
        System.out.println(Arrays.toString(scores));

    }

3、Lambda表达式(JDK 8开始):
在这里插入图片描述

示例代码


 public static void main(String[] args) {
        Collection<String> lists = new ArrayList<>();
        lists.add("赵敏");
        lists.add("小昭");
        lists.add("殷素素");
        lists.add("周芷若");
        System.out.println(lists);
        // [赵敏, 小昭, 殷素素, 周芷若]
        //  s
        lists.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        //Lambda表达式遍历的改进版
        lists.forEach(s -> { System.out.println(s); });
        
         lists.forEach(s ->  System.out.println(s) );
         //方法引用遍历方式
         lists.forEach(System.out::println );

    }

集合中存储的是元素对象的地址
在这里插入图片描述


2.数据结构(红黑树)

是计算机底层存储,组织数据的方式

红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构

它的节点可以是红或者黑根节点、叶节点Nil必须是黑色的,且不能出现两个红色节点相连的情况,红黑树不是通过高度平衡的,它的平衡是通过红黑规则进行的。对每一个节点,从该节点到其所有后代节点的简单路径上,均包含相同数目的黑色节点
在这里插入图片描述

红黑树添加节点默认用红色效率高

在这里插入图片描述
在这里插入图片描述


3.List(ArrayList,LinkedList)

添加的元素是有序的,可重复,有索引
ArrayList底层的数据结构是数组
LinkedList底层的数据结构是双链表,定位前后的元素是非常快的,可以实现栈和队列的功能

在这里插入图片描述

示例代码–集合遍历并删除元素可能出现的异常及改进方式



 public static void main(String[] args) {
        // 1、准备数据
        ArrayList<String> list = new ArrayList<>();
        list.add("黑黑");
        list.add("Java");
        list.add("Java");
        list.add("赵敏");
        list.add("赵敏");
        list.add("素素");
        System.out.println(list);
        // [黑黑, Java, Java, 赵敏, 赵敏, 素素]
        //        it

        // 需求:删除全部的Java信息。
        // a、迭代器遍历删除
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String ele = it.next();
            if("Java".equals(ele)){
                // 删除Java
                // list.remove(ele); // 集合删除会出毛病
                it.remove(); // 删除迭代器所在位置的元素值(没毛病)
            }
        }
        System.out.println(list);

        // b、foreach遍历删除 (会出现问题,这种无法解决的,foreach不能边遍历边删除,会出bug)
        for (String s : list) {
            if("Java".equals(s)){
                list.remove(s);
            }
        }

        // c、lambda表达式(会出现问题,这种无法解决的,Lambda遍历不能边遍历边删除,会出bug)
        list.forEach(s -> {//底层的逻辑是foreach()
            if("Java".equals(s)){
                list.remove(s);
            }
        });

        // d、for循环(边遍历边删除集合没毛病,但是必须从后面开始遍历删除才不会出现漏掉应该删除的元素)
        for (int i = list.size() - 1; i >= 0 ; i--) {
            String ele = list.get(i);
            if("Java".equals(ele)){
                list.remove(ele);
            }
        }
        System.out.println(list);
    }



4.泛型(泛型类、泛型方法、泛型接口、通配符)

在编译阶段约束操作的数据类型,并进行检查
泛型只能支持引用数据类型,集合体系的全部接口和实现类都是支持泛型的使用的

泛型的好处是统一数据类型,把运行时期的问题提前到编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来
在这里插入图片描述

泛型类定义类的同时定义了泛型的类就是泛型类

在这里插入图片描述

示例代码


public class MyArrayList<E> {
    private ArrayList lists = new ArrayList();
//套壳子,内部用的还是ArrayList//装饰模式的思想-外部对象包一个内部对象
    public void add(E e){
        lists.add(e);
    }

    public void remove(E e){//这个方法不是泛型方法,e是类上面定义的
        lists.remove(e);
    }

    @Override
    public String toString() {
        return lists.toString();
    }
}


 public static void main(String[] args) {
        // 需求:模拟ArrayList定义一个MyArrayList ,关注泛型设计
        MyArrayList<String> list = new MyArrayList<>();
        list.add("Java");
        list.add("Java");
        list.add("MySQL");
        list.remove("MySQL");
        System.out.println(list);

        MyArrayList<Integer> list2 = new MyArrayList<>();
        list2.add(23);
        list2.add(24);
        list2.add(25);
        list2.remove(25);
        System.out.println(list2);
    }

泛型方法—定义方法时的同时定义了泛型的方法就是泛型方法`

在这里插入图片描述

示例代码


public class GenericDemo {
    public static void main(String[] args) {
        String[] names = {"小璐", "蓉容", "小何"};
        printArray(names);

        Integer[] ages = {10, 20, 30};
        printArray(ages);

        Integer[] ages2 = getArr(ages);
        String[]  names2 = getArr(names);
    }

    public static <T> T[] getArr(T[] arr){
        return arr;
    }

    public static <T> void printArray(T[] arr){
        if(arr != null){
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0; i < arr.length; i++) {
                sb.append(arr[i]).append(i == arr.length - 1 ? "" : ", ");
            }
            sb.append("]");
            System.out.println(sb);
        }else {
            System.out.println(arr);
        }
    }
}



泛型接口 使用了泛型定义的接口就是泛型接口,可以让实现类选择当前功能需要操作的数据类型

在这里插入图片描述

示例代码 泛型接口可以约束实现类,实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都是针对该类型的操作

//定义了一个泛型接口
public interface Data<E> {
    void add(E e);
    void delete(int id);
    void update(E e);
    E queryById(int id);
}


public class Student {
}
public class StudentData implements Data<Student>{
    @Override
    public void add(Student student) {

    }

    @Override
    public void delete(int id) {

    }

    @Override
    public void update(Student student) {

    }

    @Override
    public Student queryById(int id) {
        return null;
    }
}

通配符可以在使用泛型的时候代表一切类型,ETKV实在定义泛型的时候使用的

案例-开发一个极品飞车的游戏,所有汽车都能一起参加比赛。

示例代码

public class GenericDemo {
    public static void main(String[] args) {
        ArrayList<BMW> bmws = new ArrayList<>();
        bmws.add(new BMW());
        bmws.add(new BMW());
        bmws.add(new BMW());
        go(bmws);

        ArrayList<BENZ> benzs = new ArrayList<>();
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        go(benzs);

        ArrayList<Dog> dogs = new ArrayList<>();
        dogs.add(new Dog());
        dogs.add(new Dog());
        dogs.add(new Dog());
        // go(dogs);
    }

    /**
       所有车比赛
     */
    //虽然BMW和BENZ都继承了Car但是 ArrayList<BENZ>, ArrayList<BENZ>,ArrayList< Car>是没有关系的
    //这时BWM和BENZ是不能同时调用go()的
    public static void go(ArrayList< Car> cars){
        
    }
    //于是出现了以下的解决方法,通配符?,但是此时的写法,定义的Dog也可以调用go()方法参加比赛
    public static void go(ArrayList<?> cars){
    }
    //所以出现以下正确的写法-泛型上限,必须是Car或者子类才能调用go()方法
    public static void go(ArrayList<? extends Car> cars){
    }
}

class Dog{

}

class BENZ extends Car{
}

class BMW extends Car{
}

// 父类
class Car{
}

? extends Car: ?必须是Car或者其子类 ,泛型上限
? super Car : ?必须是Car或者其父类,泛型下限


5.Set(HashSet,LInkedHashSet,TreeSet)

HashSet:无序,不重复,无索引,LInkedHashSet:有序.不重复,无索引
TreeSet:按照大小默认升序排序,不重复,无索引所以不能使用普遍for循环遍历,也不能用索引来获取元素

1、HashSet(底层采取哈希表存储数据)哈希表是增删改查性能较好的结构

JDK8之前,底层使用数组+链表组成
JDK之后,底层采用数组+链表+红黑树组成
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、LInkedHashSet有序(HashSet的子类,底层依然是哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序)

在这里插入图片描述

3、TreeSet可排序(默认从小到大排序,底层基于红黑树的数据结构实现排序的)

示例代码-自定义比较规则-如果TreeSet集合存储的对象有实现比较规则,集合也自带比较器,默认使用集合自带的比较器排序

//方式一:让自定义类实现Comparable接口,重写里面的compareTo方法来定制比较规则
public class Apple implements Comparable<Apple>{
  private String name;
    private String color;
    private double price;
    private int weight;

    public Apple() {
    }

    public Apple(String name, String color, double price, int weight) {
        this.name = name;
        this.color = color;
        this.price = price;
        this.weight = weight;
    }
....
....
....
 @Override
    public int compareTo(Apple o) {
        // 按照重量进行比较的
        return this.weight - o.weight ; // 去重重量重复的元素
        // return this.weight - o.weight >= 0 ? 1 : -1; // 保留重量重复的元素
    }
}
}



//方式二:TreeSet集合有参数构造器,可以设置Comparator接口对应的比较器对象来制定比较规则

  Set<Apple> apples = new TreeSet<>(new Comparator<Apple>() {
            @Override
            public int compare(Apple o1, Apple o2) {
                // return o1.getWeight() - o2.getWeight(); // 升序
                // 注意:浮点型建议直接使用Double.compare进行比较(内部已经写好比较规则了)
                 return Double.compare(o1.getPrice() , o2.getPrice()); // 升序
                
            }
        });
        //Lambda省略写法
   Set<Apple> apples = new TreeSet<>(( o1,  o2) ->  Double.compare(o2.getPrice() , o1.getPrice())  );

Collection大总结

在这里插入图片描述


6.Collections(集合工具类)

Collections并不属于集合,是用来操作集合的工具类

在这里插入图片描述
在这里插入图片描述

示例代码

 Collections.addAll(list, 12, 23, 2, 4);
 Collections.sort(apples, ( o1,  o2) ->  Double.compare(o1.getPrice() , o2.getPrice()) );

案例-斗地主游戏

在这里插入图片描述

示例代码

/
public class Card {
    private String size;
    private String color;
    private int index; // 牌的真正大小

    public Card(){
    }

    public Card(String size, String color, int index) {
        this.size = size;
        this.color = color;
        this.index = index;
    }
...
...

    @Override
    public String toString() {
        return size + color;
    }
}

/

public class GameDemo {
    /**
      1、定义一个静态的集合存储54张牌对象
     */
    //多态的定义方式
     public static List<Card> allCards = new ArrayList<>();

    /**
      2、做牌:定义静态代码块初始化牌数据
     */
    static {
        // 3、定义点数:个数确定,类型确定,使用数组
        String[] sizes = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
        // 4、定义花色:个数确定,类型确定,使用数组
        String[] colors = {"♠", "♥", "♣", "♦"};
        // 5、组合点数和花色
        int index = 0; // 记录牌的大小
        for (String size : sizes) {
            index++;
            for (String color : colors) {
                // 6、封装成一个牌对象。
                Card c = new Card(size, color, index);
                // 7、存入到集合容器中去
                allCards.add(c);
            }
        }
        // 8 大小王存入到集合对象中去 "👲" , "🃏"
        Card c1 = new Card("" ,  "🃏", ++index);
        Card c2 = new Card("" ,  "👲",++index);
        Collections.addAll(allCards , c1 , c2);
        System.out.println("新牌:" + allCards);
    }

    public static void main(String[] args) {
        // 9、洗牌
        Collections.shuffle(allCards);//可以打乱集合中的顺序
        System.out.println("洗牌后:" + allCards);

        // 10、发牌(定义三个玩家,每个玩家的牌也是一个集合容器)
        List<Card> linhuchong = new ArrayList<>();
        List<Card> jiumozhi = new ArrayList<>();
        List<Card> renyingying = new ArrayList<>();

        // 11、开始发牌(从牌集合中发出51张牌给三个玩家,剩余3张作为底牌)
        // allCards = [🃏, A♠, 5♥, 2♠, 2♣, Q♣, 👲, Q♠ ...
        //    i        0  1   2   3   4   5    6  7      %  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);
            }
        }

        // 12、拿到最后三张底牌(把最后三张牌截取成一个子集合)subList--开始索引-结束索引可以截取一些牌
        List<Card> lastThreeCards = allCards.subList(allCards.size() - 3 , allCards.size());

        // 13、给玩家的牌排序(从大到小 可以自己先试试怎么实现)
        sortCards(linhuchong);
        sortCards(jiumozhi);
        sortCards(renyingying);

        // 14、输出玩家的牌:
        System.out.println("啊冲:" + linhuchong);
        System.out.println("啊鸠:" + jiumozhi);
        System.out.println("盈盈:" + renyingying);
        System.out.println("三张底牌:" + lastThreeCards);
    }

    /**
       给牌排序
     * @param cards
     */
    private static void sortCards(List<Card> cards) {
        // cards = [J♥, A♦, 3♥, 🃏, 5♦, Q♥, 2♥
          // 调用Collection的sort方法
        Collections.sort(cards, new Comparator<Card>() {
            @Override
            public int compare(Card o1, Card o2) {
                // o1 = J♥
                // o2 = A♦
                // 知道牌的大小,才可以指定规则
                return o2.getIndex() - o1.getIndex();
            }
        });
    }

}



7.Map(键值对集合)

实现类:HashMap、LinkedHashMap、TreeMap:无序、有序、排序(对键排序)(不重复、无索引)
键和值都可以存null
Set系列集合(存键数据,不要值数据)的底层是Map实现的
在这里插入图片描述
Map是双列集合的祖宗接口,它的功能是全部双列集合都可以继承使用的
在这里插入图片描述

Map集合的遍历方式

1、键找值先获取Map集合全部的键,再根据遍历键找值
在这里插入图片描述

示例代码

  // 1、键找值:第一步:先拿到集合的全部键。
        Set<String> keys = maps.keySet();
        // 2、第二步:遍历每个键,根据键提取值
        for (String key : keys) {
            int value = maps.get(key);
            System.out.println(key + "===>" + value);
        }


2、键值对把“键值对”看成一个整体

在这里插入图片描述

示例代码

// 1、把Map集合转换成Set集合
        Set<Map.Entry<String, Integer>> entries = maps.entrySet();
        // 2、开始遍历
        for(Map.Entry<String, Integer> entry : entries){
            String key = entry.getKey();
            int value = entry.getValue();
            System.out.println(key + "====>" + value);
        }

3、Lambda表达式(JDK1.8开始之后的新技术)

在这里插入图片描述

示例代码

//内部帮助了遍历
  maps.forEach(new BiConsumer<String, Integer>() {
            @Override
            public void accept(String key, Integer value) {
                System.out.println(key + "--->" + value);
            }
        });

        maps.forEach((k, v) -> {
                System.out.println(k + "--->" + v);
        });

案例-统计投票人数

在这里插入图片描述

示例代码


public class MapTest1 {
    public static void main(String[] args) {
         // 1、把80个学生选择的数据拿进来。
        String[] selects = {"A" , "B", "C", "D"};
        StringBuilder sb = new StringBuilder();
        Random r = new Random();
        for (int i = 0; i < 80; i++) {
            sb.append(selects[r.nextInt(selects.length)]);
        }
        System.out.println(sb);

        // 2、定义一个Map集合记录最终统计的结果: A=30 B=20 C=20 D=10  键是景点 值是选择的数量
        Map<Character, Integer> infos = new HashMap<>(); //

        // 3、遍历80个学生选择的数据
        for (int i = 0; i < sb.length(); i++) {
            // 4、提取当前选择景点字符
            char ch = sb.charAt(i);
            // 5、判断Map集合中是否存在这个键
            if(infos.containsKey(ch)){
                 // 让其值 + 1
                infos.put(ch , infos.get(ch) + 1);
            }else {
                // 说明此景点是第一次被选
                infos.put(ch , 1);
            }
        }
        // 4、输出集合
        System.out.println(infos);

    }
}



8.集合嵌套

案例-统计投票人数

在这里插入图片描述

示例代码


public class MapTest4 {
    public static void main(String[] args) {
        // 1、要求程序记录每个学生选择的情况。
        // 使用一个Map集合存储。
        Map<String, List<String>> data = new HashMap<>();

        // 2、把学生选择的数据存入进去。
        List<String> selects = new ArrayList<>();
        Collections.addAll(selects, "A", "C");
        data.put("罗勇", selects);

        List<String> selects1 = new ArrayList<>();
        Collections.addAll(selects1, "B", "C" , "D");
        data.put("胡涛", selects1);

        List<String> selects2 = new ArrayList<>();
        Collections.addAll(selects2 , "A",  "B", "C" , "D");
        data.put("刘军", selects2);

        System.out.println(data);

        // 3、统计每个景点选择的人数。
        Map<String, Integer> infos = new HashMap<>(); // {}

        // 4、提取所有人选择的景点的信息。
        Collection<List<String>> values = data.values();
        System.out.println(values);
        // values = [[A, B, C, D], [B, C, D], [A, C]]
        //             value

        for (List<String> value : values) {
            for (String s : value) {
                // 有没有包含这个景点
                if(infos.containsKey(s)){
                    infos.put(s, infos.get(s) + 1);
                }else {
                    infos.put(s , 1);
                }
            }
        }

        System.out.println(infos);
    }
}



四、不可变集合、Stream、异常


1.不可变集合

不重复、不修改
集合的数据项在创建的时候提供,并且在整个生命周期中都不可改变,否则报错

在这里插入图片描述


2.Stream

简化集合、数组操作的API。结合了Lambda表达式

示例代码-集合获取流的方法



  /** --------------------Collection集合获取流-------------------------------   */
        Collection<String> list = new ArrayList<>();
        Stream<String> s =  list.stream();

        /** --------------------Map集合获取流-------------------------------   */
        Map<String, Integer> maps = new HashMap<>();
        // 键流
        Stream<String> keyStream = maps.keySet().stream();
        // 值流
        Stream<Integer> valueStream = maps.values().stream();
        // 键值对流(拿整体)
        Stream<Map.Entry<String,Integer>> keyAndValueStream =  maps.entrySet().stream();

        /** ---------------------数组获取流------------------------------   */
        String[] names = {"赵敏","小昭","灭绝","周芷若"};
        Stream<String> nameStream = Arrays.stream(names);
        Stream<String> nameStream2 = Stream.of(names);

在这里插入图片描述
在这里插入图片描述
终结流调用后无法继续使用了,原因是不会返回Stream,中间方法可以继续使用,支持链式编程

案例

在这里插入图片描述

示例代码

//员工类
public class Employee {
    private String name;
    private char sex;
    private double salary;
    private double bonus;
    private String punish; // 处罚信息

...
...
...
}

//优秀员工类
public class Topperformer {
    private String name;
    private double money; // 月薪

}

public class StreamDemo04 {
    public static double allMoney ;//共享变量属于类,来辅助求和操作
    public static double allMoney2 ; // 2个部门去掉最高工资,最低工资的总和
    public static void main(String[] args) {
        List<Employee> one = new ArrayList<>();
        one.add(new Employee("猪八戒",'男',30000 , 25000, null));
        one.add(new Employee("孙悟空",'男',25000 , 1000, "顶撞上司"));
        one.add(new Employee("沙僧",'男',20000 , 20000, null));
        one.add(new Employee("小白龙",'男',20000 , 25000, null));


        List<Employee> two = new ArrayList<>();
        two.add(new Employee("武松",'男',15000 , 9000, null));
        two.add(new Employee("李逵",'男',20000 , 10000, null));
        two.add(new Employee("西门庆",'男',50000 , 100000, "被打"));
        two.add(new Employee("潘金莲",'女',3500 , 1000, "被打"));
        two.add(new Employee("武大郎",'女',20000 , 0, "下毒"));

        // 1、开发一部的最高工资的员工。(API)
        // 指定大小规则了
//        Employee e = one.stream().max((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(),  e2.getSalary() + e2.getBonus()))
//                .get();
//       System.out.println(e);
        //找出优秀员工以后封装成一个优秀员工
        Topperformer t = one.stream().max((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(),  e2.getSalary() + e2.getBonus()))
                .map(e -> new Topperformer(e.getName(),  e.getSalary() + e.getBonus())).get();
        System.out.println(t);

        // 2、统计平均工资,去掉最高工资和最低工资
        one.stream().sorted((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(),  e2.getSalary() + e2.getBonus()))
                .skip(1).limit(one.size() - 2).forEach(e -> {
            //先排序,跳过第一个,截取前two.size() - 2的位置,刚好就把最低、最高工资去掉了
                    // 求出总和:剩余员工的工资总和
            allMoney += (e.getSalary() + e.getBonus());
        });
        System.out.println("开发一部的平均工资是:" + allMoney / (one.size() - 2));

        // 3、合并2个集合流,再统计
        Stream<Employee> s1 = one.stream();
        Stream<Employee> s2 = two.stream();
        Stream<Employee> s3 = Stream.concat(s1 , s2);
        s3.sorted((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(),  e2.getSalary() + e2.getBonus()))
                .skip(1).limit(one.size() + two.size() - 2).forEach(e -> {
            // 求出总和:剩余员工的工资总和
            allMoney2 += (e.getSalary() + e.getBonus());
        });

        // BigDecimal-可以解决精度问题
        BigDecimal a = BigDecimal.valueOf(allMoney2);//封装起来
        BigDecimal b = BigDecimal.valueOf(one.size()  + two.size() - 2);
        System.out.println("开发部的平均工资是:" + a.divide(b,2, RoundingMode.HALF_UP));//四舍五入进行留位
    }
}



Stream流的收集:把操作后的结果数据转回到集合或者数组中去

Stream流只是方便操作集合、数组的手段,集合、数组才是开发中的目的

在这里插入图片描述

示例代码


public class StreamDemo05 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.add("张三丰");

        Stream<String> s1 = list.stream().filter(s -> s.startsWith("张"));
        // 收集到可变集合中去    //遍历六中的数据封装到ArrayList中去再赋值给List
        List<String> zhangList = s1.collect(Collectors.toList()); 
        zhangList.add("java1");
        System.out.println(zhangList);

        // 得到不可变集合
//        toList();是JDK16开始的API
//       List<String> list1 = s1.toList(); 
//       list1.add("java");
//       System.out.println(list1);

        // 注意注意注意:“流只能使用一次”
        //拿一个新流
        Stream<String> s2 = list.stream().filter(s -> s.startsWith("张"));
        Set<String> zhangSet = s2.collect(Collectors.toSet());
        System.out.println(zhangSet);
        //收集到数组中
        Stream<String> s3 = list.stream().filter(s -> s.startsWith("张"));
//         Object[] arrs = s3.toArray();//流中可能有其它类型,不光是字符串类型,所以用Object
          //申明一个对象告诉电脑我就是字符串类型
//        String[] arrs = s3.toArray(new IntFunction<String[]>() {
//            @Override
//            public String[] apply(int value) {
//                return new String[value];//
//            }
//        });
// 简化
        String[] arrs = s3.toArray(s-> new String[s]);
//        简化
//        String[] arrs = s3.toArray(String[]::new);
        System.out.println("Arrays数组内容:" + Arrays.toString(arrs));

    }
}


3.异常

异常是程序在“编译”或者“执行”的过程中可能出现的问题
语法错误不算在异常体系中

异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止
研究、处理异常,体现的是程序的安全、健壮性
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

异常默认的处理流程

在这里插入图片描述

编译时异常的处理机制

在这里插入图片描述
在这里插入图片描述
异常处理的第三种,方法直接将异常通过throws抛出去给调用者,调用者收到异常后直接捕获异常

运行时异常的处理机制不需主动抛异常

运行时异常编译阶段不会出错,是运行时才可能出错,所以编译阶段不处理也可以。按规范,再外层调用处集中捕获处理即可。

案例

在这里插入图片描述

示例代码


public class Test2 {
    public static void main(String[] args) {
        Scanner sc  = new Scanner(System.in);
        while (true) {
            try {//实际开发中也可以使用正则表达式来校验输入是否合法
                System.out.println("请您输入合法的价格:");
                String priceStr = sc.nextLine();//接收一行的数据
                // 转换成double类型的价格
                double price = Double.valueOf(priceStr);

                // 判断价格是否大于 0
                if(price > 0) {
                    System.out.println("定价:" + price);
                    break;
                }else {
                    System.out.println("价格必须是正数~~~");
                }
            } catch (Exception e) {
                System.out.println("用户输入的数据有毛病,请您输入合法的数值,建议为正数~~");
            }
        }
    }
}

自定义异常类

Java无法为所有的问题提供异常类,若开发中需要,则需自定义异常类
自定义异常类,可以使用异常的机制管理业务问题,同时一旦出现bug,可以用异常的形式清晰的指出出错的地方

在这里插入图片描述

示例代码

/**
    自定义的编译时异常
      1、继承Exception
      2、重写构造器
 */
public class ItheimaAgeIlleagalException extends Exception{
    public ItheimaAgeIlleagalException() {
    }

    public ItheimaAgeIlleagalException(String message) {
        super(message);
    }
}

/**
    自定义的运行时异常
      1、继承RuntimeException
      2、重写构造器
 */
public class ItheimaAgeIlleagalRuntimeException extends RuntimeException{
    public ItheimaAgeIlleagalRuntimeException() {
    }

    public ItheimaAgeIlleagalRuntimeException(String message) {
        super(message);
    }
}


总结

以上就是在网上学习java做的笔记,用于以后的巩固复习,若能帮助到网络上的同行者就更好啦!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值