18Java基础之API(二)

arrays

  • 用于操作数组的一个工具类。
    image

如果数组中存储的是对象,如何排序?

  1. 让该对象的类实现Comparable(比较规则)接口,然后重写compareTo方法,自己来制定比较规则。
  2. 使用下面sort方法,创建comparator比较器接口的匿名内部类对象,然后自己制定比较规则。
    public static void sort(T[] arr, Comparator<?super T> c) 对数组进行排序(支持自定义排序规则)

3.compareTo()方法中,JAVA官方规定:

  • 如果认为左边大于右边,请返回正整数;
  • 如果认为左边小于右边,请返回负整数;
  • 如果认为左边等于右边,请返回0;
  • 这么干,默认就是升序排列;

案例:

学生类:
package com.javabase.d1_arrays;

public class Student implements Comparable<Student>{
    private String name;
    private int age;
    private char gender;
    private double height;

    public Student() {
    }

    public Student(String name, int age, char gender, double height) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.height = height;
    }

    // 自定义排序规则方式一:让对象所在的类实现比较规则接口Comparable,重写CompareTo方法,来指定比较规则。
    // 指定大小规则
    // 比较者:this
    // 被比较者:o
    @Override
    public int compareTo(Student o) {
        /*
        * 官方定制规则:
        * 如果认为左边大于右边,请返回正整数
        * 如果认为左边小于右边,请返回负整数
        * 如果认为左边等于右边,请返回0
        * 只有这么干,默认就是升序排列
        * */
//        if(this.age > o.age) return 1;
//        else if(this.age < o.age) return -1;
//
//        return 0;
        return this.age -o.age; // 年龄升序
        return o.age - this.age;// 年龄降序
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

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

测试:
//目标:给存储对象的数组进行排序
public class ArraysDemo02 {
    public static void main(String[] args) {
        Student[] students = new Student[4];
        students[0] = new Student("张三", 18, '男', 1.88);
        students[1] = new Student("李四", 19, '女', 1.68);
        students[2] = new Student("王五", 20, '男', 1.78);
        students[3] = new Student("赵六", 21, '女', 1.98);

        Arrays.sort(students);// 报错
        System.out.println(Arrays.toString(students));
        System.out.println("-----------------------------");

        // 自定义排序规则方式二:sort存在重载的方法,支持自带Comparator比较器对象来直接指定比较规则(优先使用,就近原则)
        // public static <T> void sort(T[] a, Comparator<? super T> c)
        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
//                return o1.getAge() - o2.getAge();
                return Double.compare(o1.getHeight(), o2.getHeight());
            }
        });
    }
}

**注意:**自定义排序二中,对象比较时,如果是整型,则可以直接减,然后返回结果。如果是double类型,则需要调用Double.compare()方法来进行比较,然后将结果返回。

Lambda表达式

  • Lambda表达式是JDK8开始新增的一种语法形式;
  • 作用:用于简化匿名内部类的代码写法。
  • 格式:
    (被重写方法的形参列表)->{
    被重写方法的方法体代码;
    }

注意:Lambda表达式只能简化函数式接口的匿名内部类!!!

什么是函数式接口?

  • 有且仅有一个抽象方法的接口。
  • 注意:以后我们见到的大部分函数式接口,上面都可能会有一个@FunctionalInterface的注解,有该注解的接口就必定是函数式接口。

案例:

// 目标:认识Lambda是如何简化匿名内部类的
public class Test01 {
    public static void main(String[] args) {
        Animal a1 = new Animal() {
            @Override
            public void run() {
                System.out.println("老虎跑的贼快!");
            }
        };
        a1.run();

        // 错误示范:Lambda并不能简化所有匿名内部类的代码。只能简化函数式接口的匿名内部类。
//        Animal a2 = () ->{
//            System.out.println("老虎跑的贼快!");
//        };
//        a2.run();
        //Lambda可以简化函数式接口的匿名内部类
        // 之所以可以简化代码,是因为它可以通过上下文推断出真实的代码形式;
        Swiming s1 = () ->{
            System.out.println("我游泳速度贼快!");
        };
        s1.swim();
    }
}

@FunctionalInterface //函数式接口,有且只有一个抽象方法
interface Swiming{
    void swim();
}

abstract class Animal{
    public abstract void run();
}

案例:lambda表达式简化的例子

import java.util.Arrays;
import java.util.Comparator;
import java.util.function.IntToDoubleFunction;

//目标:掌握Lambda表达式简化常见函数式接口的匿名内部类
public class Test02 {
    public static void main(String[] args) {
        double[] scores = {95.5, 86.1, 55.6, 86,96,88.2};
       /* Arrays.setAll(scores, new IntToDoubleFunction() {
            @Override
            public double applyAsDouble(int index) {
                return scores[index] + 10;
            }
        });*/
        Arrays.setAll(scores, (int index) ->{
                return scores[index] + 10;
        });

        System.out.println(Arrays.toString(scores));

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

        Student[] students = new Student[4];
        students[0] = new Student("张三", 18, '男', 1.88);
        students[1] = new Student("李四", 19, '女', 1.68);
        students[2] = new Student("王五", 20, '男', 1.78);
        students[3] = new Student("赵六", 21, '女', 1.98);

        System.out.println(Arrays.toString(students));
        System.out.println("-----------------------------");

        /*Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
//                return o1.getAge() - o2.getAge();
                return Double.compare(o1.getHeight(), o2.getHeight());
            }
        });*/
        Arrays.sort(students,(Student o1, Student o2) ->{
//                return o1.getAge() - o2.getAge();
                return Double.compare(o1.getHeight(), o2.getHeight());
        });
    }
}

Lambda表达式的省略写法(进一步简化Lambda表达式的写法)

  • 参数类型可以省略不写
  • 如果只有一个参数,参数类型可以省略,同时()也可以省略
  • 如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号。此时,如果这行代码是return语句,也必须去掉return不写。

案例:

public class Test02 {
    public static void main(String[] args) {
        double[] scores = {95.5, 86.1, 55.6, 86,96,88.2};
       /* Arrays.setAll(scores, new IntToDoubleFunction() {
            @Override
            public double applyAsDouble(int index) {
                return scores[index] + 10;
            }
        });*/
        Arrays.setAll(scores, (int index) ->{
                return scores[index] + 10;
        });

        System.out.println(Arrays.toString(scores));

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

        Student[] students = new Student[4];
        students[0] = new Student("张三", 18, '男', 1.88);
        students[1] = new Student("李四", 19, '女', 1.68);
        students[2] = new Student("王五", 20, '男', 1.78);
        students[3] = new Student("赵六", 21, '女', 1.98);

        // Lambda规则
        //1. 参数类型可以不写
        Arrays.setAll(scores, (index) ->{
            return scores[index] + 10;
        });

        Arrays.sort(students,(o1, o2) ->{
//                return o1.getAge() - o2.getAge();
            return Double.compare(o1.getHeight(), o2.getHeight());
        });
        //2. 如果只有一个参数,参数类型可以省略,同时()也可以省略
        Arrays.setAll(scores, index ->{
            return scores[index] + 10;
        });
        //3. 如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号。
        // 此时,如果这行代码是return语句,也必须去掉return不写
        Arrays.sort(students,(o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight()));
//                return o1.getAge() - o2.getAge();

        Arrays.setAll(scores, index -> scores[index] + 10);
    }
}

JDK8新特性:方法引用

  • 静态方法的引用
    • 类名::静态方法。

使用场景

  • 如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用了。
    案例
学生类:(沿用之前创建的学生类,只是新增了方法)
 public static int compareByHeight(Student o1, Student o2){
        return Double.compare(o1.getHeight(), o2.getHeight());
    }

测试方法:
public class Test03 {
    public static void main(String[] args) {
        Student[] students = new Student[4];
        students[0] = new Student("张三", 18, '男', 1.88);
        students[1] = new Student("李四", 19, '女', 1.68);
        students[2] = new Student("王五", 20, '男', 1.78);
        students[3] = new Student("赵六", 21, '女', 1.98);

//        Arrays.sort(students,(o1, o2) -> Student.compareByHeight(o1, o2));
        Arrays.sort(students,Student::compareByHeight);//终极写法:静态引用
        System.out.println(Arrays.toString(students));
    }
}

实例方法引用

  • 对象名::实例方法

使用场景

  • 如果某个Lambda表达式里只有调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法引用了。
    案例:
public class Test04 {
    public static void main(String[] args) {
        Student[] students = new Student[4];
        students[0] = new Student("张三", 18, '男', 1.88);
        students[1] = new Student("李四", 19, '女', 1.68);
        students[2] = new Student("王五", 20, '男', 1.78);
        students[3] = new Student("赵六", 21, '女', 1.98);

//        Arrays.sort(students,(o1,o2)-> Double.compare(o1.getHeight(),o2.getHeight()));

        Test04 t = new Test04();
        Arrays.sort(students,t::compare);
    }
    public int  compare(Student o1, Student o2){
        return Double.compare(o1.getHeight(),o2.getHeight());
    }
}

特定类型方法的引用

  • 类型::方法

使用场景

  • 如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。
    案例
//目标:特定类型的方法引用
public class Test05 {
    public static void main(String[] args) {
        String[] names = {"dlei", "Angela", "baby", "caocao", "Coach", "曹操", "deby", "eason", "andy"};
        //对它们进行排序,按照首字母编号排序
        Arrays.sort(names);
        System.out.println(Arrays.toString(names));

       /* Arrays.sort(names, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareToIgnoreCase(o2);
            }
        });*/

        Arrays.sort(names, (o1, o2) -> o1.compareToIgnoreCase(o2));
        Arrays.sort(names, String::compareToIgnoreCase);
    }
}

构造器引用

  • 类名::new

使用场景

  • 如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用。
    案例
//目标:掌握构造器引用
public class Test06 {
    public static void main(String[] args) {
        /*Create c1 = new Create() {
            @Override
            public Car createCar(String name) {
                return new Car(name);
            }
        };*/
//        Create c1 = name-> new Car(name);
        Create c1 = Car::new;

        Car car = c1.createCar("布加迪威龙");
        System.out.println(car);

    }

    @FunctionalInterface //函数式接口
    interface Create{
        Car createCar(String name);
    }
    
    static class Car{
        private String name;

        public Car(){}

        public Car(String name){
            this.name = name;
        }

        @Override
        public String toString() {
            return "Car{" +
                    "name='" + name + '\'' +
                    '}';
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

什么是算法?

  • 解决某个实际问题的过程和方法。

学习算法的技巧

  1. 搞清楚算法的流程
  2. 直接去推敲如何写代码。

排序算法

  • 冒泡排序
    • 每次从数组中找出最大值放在数组的后面去。
    • 实现冒泡排序的关键步骤分析:
      • 假设数组为:int[] arr = {5, 2, 3, 1};
      • 确定总共需要几轮:数组的长度-1
      • 每轮比较几次;
        image
      • 当前位置大于后一个位置则交换数据
// 目标:完成冒泡排序。
public class Demo01 {
    public static void main(String[] args) {
        //1.定义数组
        int[] arr = {5, 2, 3 ,1, 4};

        //2. 定义一个循环控制冒泡的轮数
        for(int i = 0; i < arr.length -1; i++){
            // 轮数(i) 每轮比较的次数  j的占位
            //  0          4            0 1 2 3
            //  1          3            0 1 2
            //  2          2            0 1
            //  3          1            0
            //3. 定义内部循环要控制每轮比较次数
            for(int j = 0; j < arr.length - i - j; j++){
               // 4.判断当前位置j是否大于其后一个位置处的数据。若较大,则交换。
                if(arr[j] > arr[j + 1]){
                    //5. 定义一个临时变量记住较大的值。
                    int  temp = arr[j];
                    //6. 把前一个数据赋值给后一个,把临时的变量赋值给前一个。
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}
  • 选择排序
  • 每轮选择当前位置,开始找出后面的较小值与该位置交换。
//目标:实现选择排序
public class Demo02 {
    public static void main(String[] args) {
        //1. 定义一个数组
        int[] arr = {5, 1, 3, 2, 4};

        //2. 定义一个循环,控制循环几轮
        for (int i = 0; i < arr.length -1; i++) {
            //3. 定义一个循环,控制每轮比较几次
            /*
            * 轮数(i)  次数   j的占位
            *  0        4       1 2 3 4
            *  1        3       2 3 4
            *  2        2       3 4
            *  3        1       4
            * */
            for(int j = i + 1; j < arr.length; j++){
                //4. 判断j位置的元素是否小于i位置的元素,如果小于,交换位置
                if(arr[i] > arr[j]){
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }

        System.out.println(Arrays.toString(arr));
    }
}

排序算法的升级版

//目标:实现选择排序
public class Demo02_2 {
    public static void main(String[] args) {
        //1. 定义一个数组
        int[] arr = {5, 1, 3, 2, 4};

        //2. 定义一个循环,控制循环几轮
        for (int i = 0; i < arr.length -1; i++) {
            int minIndex = i;
            for(int j = i + 1; j < arr.length; j++){
                //4. 判断j位置的元素是否小于i位置的元素,如果小于,交换位置
                if(arr[minIndex] > arr[j]){
                    minIndex = j;
                }
            }
            if(minIndex != i){
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }

        }

        System.out.println(Arrays.toString(arr));
    }
}

查找算法

  • 基本查找/顺序查找
    image
    注意:在数据量特别大的时候,基本查找这种从前往后挨个找的形式,性能是很差的。

二分查找(折半查找)

  • 前提条件:数组中的数据必须是有序的。
  • 核心思想:每次排除一般的数据,查询数据的性能明显提高极多。
  • 结论:二分查找正常的折半条件应该是开始位置left<=结束位置right。
    实现代码:
//目标:实现二分查找
//目标:实现二分查找
public class Demo03 {
    public static void main(String[] args) {
        int[] arr = {7, 23, 79, 81, 103, 127, 131, 147};
        int index = serchDataIndex(arr, 79);

        System.out.println("79的索引是:" + index);

        int index2 = serchDataIndex(arr, 150);
        System.out.println("150的索引是:" + index2);
    }

    public static int serchDataIndex(int[] arr, int key) {
        //1. 定义两个变量,记录要查找的范围
        int start = 0;
        int end = arr.length - 1;

        //2.开始折半查询
        while (start <= end) {
            int mid = (start + end) / 2;
            //3. 判断当前位置的元素与key的大小进行比较
            if (arr[mid] == key) return mid;
            else if (arr[mid] < key) {
                //4. 往右边找:开始的指针更新为mid + 1;
                start = mid + 1;
            } else if (arr[mid] > key) {
                //5. 往左边找:结束的指针更新为mid - 1;
                end = mid - 1;
            }
        }
        return -1;
    }
}

正则表达式

  • 正则表达式是由一些特定的字符组成,代表的是一个规则。
  • 作用
    1. 用来校验数据格式是否合法。
    2. 在一段文本中查找满足要求的内容。
      代码举例
//目标:初步体验,正则表达式的作用
public class RegexTest01 {
    public static void main(String[] args) {
        System.out.println(checkQQ("23242424"));
        System.out.println(checkQQ("2324abcd2424"));
        System.out.println(checkQQ2("23242424"));
        System.out.println(checkQQ2("2324abcd2424"));
    }

    //先不用正则表达式来解决
    public static boolean checkQQ(String qq) {
        //1. 需求:要求这个qq号码必须是5位以上,全部都是数字,不能以0开头
        if(qq == null || qq.length() == 0) return false;

        //2.判断是否是数字
        for(int i = 0; i < qq.length(); i++) {
            char c = qq.charAt(i);
            if(i == 0 && c == '0') return false;
            if(c <'0' || c > '9') return false;
        }
        return true;
    }

    //使用正则表达式来解决
    public static boolean checkQQ2(String qq){
        return qq != null && qq.length() > 5 && qq.matches("[1-9]\\d{5,}");
    }
}

匹配正则表达式的方法

  • public boolean matches(String regex),判断字符串是否匹配正则表达式,匹配返回true,不匹配返回false。

正则表达式的书写规则
image

image

image

案例:

需求:校验用户输入的电话、邮箱
//目标:使用所学的正则表达式来校验数据的合法性
public class Demo01 {
    public static void main(String[] args) {
//        checkEmail();
        checkPhone();
    }

    public static void checkPhone() {
        Scanner sc = new Scanner(System.in);
        while(true){
            System.out.println("Enter your Phone Number:");
            String phone = sc.next();

            //13722162084
            //8556355
            if(phone.matches("1[3-9]\\d{9}")){
                System.out.println("手机号码合法,录入成功!");
                break;
            }
            else{
                System.out.println("您输入的手机号码不合法,请重新输入!");
            }
        }
        sc.close();
    }

    public static void checkEmail() {
        Scanner sc = new Scanner(System.in);
        while(true){
            System.out.println("Enter your email address:");
            String email = sc.next();

            //adf1234@163.com
            //8754264@qq.com
            //xunzhao@itdcx.com.cn
            if(email.matches("\\w{2,30}@\\w{2,20}(\\.\\w{2,20}){1,2}")){
                System.out.println("邮箱地址合法,录入成功!");
                break;
            }
            else{
                System.out.println("您输入的邮箱地址不合法,请重新输入!");
            }
        }
        sc.close();
    }
}

案例:使用正则表达式查找一段文本中的内容。
image
需求1:找出所有的电话号、邮箱地址、热线电话。
需求2:把每个邮箱中的用户名爬取出来。

//目标:了解使用正则表达式去文本中的爬取想要的信息
public class Demo02 {
    public static void main(String[] args) {
       String data = "来IT未来学习Java,\n"+
               "电话:18512516758,18512508907\n"+
               "或者联系邮箱: boniu@itcast.cn\n"+
               "座机电话:01036517895,010-98951256\n"+
               "邮箱:bozai@itcast.cn,\n"+
               "邮箱2:dlei0009@163.com,\n”+" +
               "热线电话:400-618-9090,400-618-4000,\n"+
               "4006184000,4006189090\n";
        // 需求:从中间爬取出邮箱,手机号,座机号,400电话号。
        //1. 定义爬取规则对象,封装爬取格式
        Pattern p = Pattern.compile("(1[3-9]\\d{9})|(\\w{2,30}@\\w{2,20}(\\.\\w{2,20}){1,2})"+
                "|(0\\d{2,6}-?[1-9]\\d{3,10})|(400-?[1-9]\\d{2,6}-?[1-9]\\d{2,6})");

        //2.通过匹配规则对象p与内容data建立联系得到一个匹配器对象
        Matcher m = p.matcher(data);

        //3. 使用匹配器对象,开始爬取内容
        while(m.find()){
            String info = m.group();
            System.out.println(info);
        }

        //需求2:把每个邮箱中的用户名爬取出来。
        Pattern p1 = Pattern.compile("(\\w{2,30})@\\w{2,20}(\\.\\w{2,20}){1,2}");

        //2.通过匹配规则对象p与内容data建立联系得到一个匹配器对象
        Matcher m1 = p1.matcher(data);

        //3. 使用匹配器对象,开始爬取内容
        while(m1.find()){
            String info = m1.group(1);//只要爬取出来的邮箱中的第一组括号中的内容
            System.out.println(info);
        }
    }
}

案例2:

public class Demo03 {
    public static void main(String[] args) {
        String data="欢迎张全蛋光临本系统!他删库并跑路欢迎李二狗子光临本系统!"+
        "欢迎马六子光临本系统!它浏览了很多好看的照片!欢迎夏洛光临本系统!他在六点钟送出了一个嘉年华!";
        //1. 指定爬取规则对象
        Pattern p = Pattern.compile("欢迎(.+?)光临");// 贪婪匹配,最大范围匹配

        //2. 让内容和爬取规则建立关系,得到一个匹配器对象。
        Matcher m = p.matcher(data);

        //3. 开始用匹配器对象爬取内容
        while(m.find()){
            System.out.println(m.group(1));
        }
    }
}

搜索替换、分割

  • 正则表达式用于搜索替换、分割内容,需要结合String提供的如下方法完成:
    image
//目标:了解使用正则表达式搜索替换、内容分割。
public class Demo04 {
    public static void main(String[] args) {
        //需求:把中间非中文字符替换成“-”
        String s1 = "古力娜扎ai8888迪丽热巴99fafas9aa5566马尔扎哈fbbADFFfsfs42425卡尔扎巴";
        String result = s1.replaceAll("\\w+", "-");
        System.out.println(result);

        //需求:把所有名字取出来
        String[] names = s1.split("\\w+");
        System.out.println(Arrays.toString(names));
    }
}
posted @ 2025-08-05 11:17  狂风将军  阅读(17)  评论(0)    收藏  举报