day15——Java常用API(二):常见算法、正则表达式与异常处理详解

文章目录

本文将深入探讨Java中三大核心技术:常见算法、正则表达式和异常处理,帮助开发者掌握这些必备技能。

一、常见算法详解

1.1 排序算法

冒泡排序

原理 :通过相邻元素比较和交换,每一轮将最大元素"冒泡"到数组末尾
关键步骤

  1. 确定轮数:数组长度-1
  2. 每轮比较次数:数组长度-当前轮数-1
  3. 相邻元素比较,顺序错误则交换
java 复制代码
// 冒泡排序实现
public static void bubbleSort(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {
        for (int j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
选择排序

原理 :每轮选择一个固定位置元素,与后面元素比较找到最小元素并交换
关键步骤

  1. 确定轮数:数组长度-1
  2. 每轮从当前位置开始向后比较
  3. 找到最小元素索引并交换
java 复制代码
// 选择排序实现
public static void selectionSort(int[] arr) {
    for (int i = 0; i < arr.length - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < arr.length; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        int temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}

1.2 查找算法

二分查找

前提 :数组必须有序
原理 :每次将查找范围缩小一半
步骤

  1. 定义左右边界(left, right)
  2. 计算中间位置 mid = (left + right) / 2
  3. 比较中间元素与目标值:
    • 目标值大:left = mid + 1
    • 目标值小:right = mid - 1
    • 相等:返回mid
  4. 循环直到left > right,未找到返回-1
java 复制代码
// 二分查找实现
public static int binarySearch(int[] arr, int target) {
    int left = 0;
    int right = arr.length - 1;
    
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == target) {
            return mid;
        } else if (arr[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return -1;
}

二、正则表达式深入解析

2.1 正则表达式基础

核心作用

  1. 数据格式校验(如手机号、邮箱验证)
  2. 文本内容提取(爬取特定信息)
  3. 文本替换与分割

基础语法


类别 表达式 说明
字符类 [abc] 匹配a、b或c
[^abc] 匹配除a、b、c外的字符
[a-zA-Z] 匹配任意字母
预定义字符 . 匹配任意单个字符
\d 匹配数字[0-9]
\D 匹配非数字
\s 匹配空白字符
\S 匹配非空白字符
数量词 X? 0或1次
X* 0或多次
X+ 1或多次
X{n} 恰好n次
X{n,} 至少n次
X{n,m} n到m次
边界匹配 ^ 行首
$ 行尾
\b 单词边界

2.2 正则表达式应用案例

测试
java 复制代码
 public static void main(String[] args) {
        // 1、字符类(只能匹配单个字符)
        System.out.println("a".matches("[abc]"));    // [abc]只能匹配a、b、c
        System.out.println("e".matches("[abcd]")); // false

        System.out.println("d".matches("[^abc]"));   // [^abc] 不能是abc
        System.out.println("a".matches("[^abc]"));  // false

        System.out.println("b".matches("[a-zA-Z]")); // [a-zA-Z] 只能是a-z A-Z的字符
        System.out.println("2".matches("[a-zA-Z]")); // false

        System.out.println("k".matches("[a-z&&[^bc]]")); // [a-z&&[^bc]] a到z,除了b和c
        System.out.println("b".matches("[a-z&&[^bc]]")); // false

        System.out.println("ab".matches("[a-zA-Z0-9]")); // false 注意:以上带 [内容] 的规则都只能用于匹配单个字符

        // 2、预定义字符(只能匹配单个字符)  .  \d  \D   \s  \S  \w  \W
        System.out.println("徐".matches(".")); // .可以匹配任意字符
        System.out.println("徐徐".matches(".")); // false

        // \转义
        System.out.println("\"");
        // \n \t
        System.out.println("3".matches("\\d"));  // \d: 0-9
        System.out.println("a".matches("\\d"));  //false

        System.out.println(" ".matches("\\s"));   // \s: 代表一个空白字符
        System.out.println("a".matches("\s")); // false

        System.out.println("a".matches("\\S"));  // \S: 代表一个非空白字符
        System.out.println(" ".matches("\\S")); // false

        System.out.println("a".matches("\\w"));  // \w: [a-zA-Z_0-9]
        System.out.println("_".matches("\\w")); // true
        System.out.println("徐".matches("\\w")); // false

        System.out.println("徐".matches("\\W"));  // [^\w]不能是a-zA-Z_0-9
        System.out.println("a".matches("\\W"));  // false

        System.out.println("23232".matches("\\d")); // false 注意:以上预定义字符都只能匹配单个字符。

        // 3、数量词: ?   *   +   {n}   {n, }  {n, m}
        System.out.println("a".matches("\\w?"));   // ? 代表0次或1次
        System.out.println("".matches("\\w?"));    // true
        System.out.println("abc".matches("\\w?")); // false

        System.out.println("abc12".matches("\\w*"));   // * 代表0次或多次
        System.out.println("".matches("\\w*"));        // true
        System.out.println("abc12张".matches("\\w*")); // false

        System.out.println("abc12".matches("\\w+"));   // + 代表1次或多次
        System.out.println("".matches("\\w+"));       // false
        System.out.println("abc12张".matches("\\w+")); // false

        System.out.println("a3c".matches("\\w{3}"));   // {3} 代表要正好是n次
        System.out.println("abcd".matches("\\w{3}"));  // false
        System.out.println("abcd".matches("\\w{3,}"));     // {3,} 代表是>=3次
        System.out.println("ab".matches("\\w{3,}"));     // false
        System.out.println("abcde徐".matches("\\w{3,}"));     // false
        System.out.println("abc232d".matches("\\w{3,9}"));     // {3, 9} 代表是  大于等于3次,小于等于9次

        // 4、其他几个常用的符号:(?i)忽略大小写 、 或:| 、  分组:()
        System.out.println("abc".matches("(?i)abc")); // true
        System.out.println("ABC".matches("(?i)abc")); // true
        System.out.println("aBc".matches("a((?i)b)c")); // true
        System.out.println("ABc".matches("a((?i)b)c")); // false

        // 需求1:要求要么是3个小写字母,要么是3个数字。
        System.out.println("abc".matches("[a-z]{3}|\\d{3}")); // true
        System.out.println("ABC".matches("[a-z]{3}|\\d{3}")); // false
        System.out.println("123".matches("[a-z]{3}|\\d{3}")); // true
        System.out.println("A12".matches("[a-z]{3}|\\d{3}")); // false

        // 需求2:必须是"我爱"开头,中间可以是至少一个"编程",最后至少是1个"666"
        System.out.println("我爱编程编程666666".matches("我爱(编程)+(666)+"));
        System.out.println("我爱编程编程66666".matches("我爱(编程)+(666)+"));
    }
数据校验
java 复制代码
// 手机号校验(支持手机和座机)
public static boolean validatePhone(String phone) {
    return phone.matches("(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})");
    //表示手机号 1开头,第二位是3-9,后面是9位的数字 
    //或 座机号:以0开头,后面区号长度2-7位,-?  -至多出现1次,开头1-9,后面4-19位的数字
}

// 邮箱校验
public static boolean validateEmail(String email) {
            /**
             * dlei0009@163.com
             * 25143242@qq.com
             * itheima@itcast.com.cn
             */
    return email.matches("\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2}");
    // \\w 可能是英文字符或数字,{2,} 2位以上,有一个@,2-20位的字符或数字,
    //有一个.  \\. 第一个\ 告诉第二个\:你就是个\,第二个\告诉后面的.:你就是个.
    //\\w{2,10}  2-10位的字符或数字
    // (\\.\\w{2,10}){1,2} 表示(\\.\\w{2,10}) 这个表达式可能出现1-2次
}
信息爬取
java 复制代码
// 从文本中提取所有电话号码
public static List<String> extractPhones(String text) {
    List<String> phones = new ArrayList<>();
    String regex = "(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(text);
    
    while (matcher.find()) {
        phones.add(matcher.group());
    }
    return phones;
}

    // 需求:从以下内容中爬取出,手机,邮箱,座机、400电话等信息。
    public static void method1(){
        String data = " 来学习Java,电话:1111111111,18699997777" +
                "        或者联系邮箱:boniufe@com.cn,\n" +
                "        热线电话:400-618-90960 40061897090";
        // 1、定义爬取规则
        //(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})  手机或座机的正则表达式
        //(\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2}) 邮箱的表达式
        //(400-?\\d{3,7}-?\\d{3,7})  400开头,-可有可无,3-7位数字
        String regex = "(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})|(\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2})"
                + "|(400-?\\d{3,7}-?\\d{3,7})";
        // 2、把正则表达式封装成一个Pattern对象
        Pattern pattern = Pattern.compile(regex);
        // 3、通过pattern对象去获取查找内容的匹配器对象。
        Matcher matcher = pattern.matcher(data);
        // 4、定义一个循环开始爬取信息
        while (matcher.find()){
            String rs = matcher.group(); // 获取到了找到的内容了。
            System.out.println(rs);
        }
    }
文本处理

正则表达式用于搜索替换、分割内容,需要结合String提供的如下方法完成:

java 复制代码
// 需求1:请把 古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴,中间的非中文字符替换成 "-"
 String s1 = "古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
 System.out.println(s1.replaceAll("\\w+", "-")); //数字或字符替换成-
// 需求2(拓展):某语音系统,收到一个口吃的人说的"我我我喜欢编编编编编编编编编编编编程程程!",需要优化成"我喜欢编程!"。
  String s2 = "我我我喜欢编编编编编编编编编编编编程程程";
        /**
         * (.)一组:.匹配任意字符的。
         * \\1 :为这个组声明一个组号:1号
         * +:声明必须是重复的字
         * $1可以去取到第1组代表的那个重复的字
         */
   System.out.println(s2.replaceAll("(.)\\1+", "$1")); 
   
// 替换所有非汉字字符
String result = text.replaceAll("[^\\u4e00-\\u9fa5]", "-");

// 按数字分割字符串
String[] parts = text.split("\\d+");

2.3 高级技巧

  1. 非贪婪匹配:在量词后加?(如.*?)
  2. 分组引用:使用()分组,$n引用分组
  3. 前瞻后顾:(?=exp)正向前瞻,(?!exp)负向前瞻
java 复制代码
// 提取用户名(非贪婪匹配)
public static List<String> extractUsernames(String text) {
    List<String> usernames = new ArrayList<>();
    Pattern pattern = Pattern.compile("欢迎(.+?)光临");
    Matcher matcher = pattern.matcher(text);
    
    while (matcher.find()) {
        usernames.add(matcher.group(1)); // 获取第一个分组
    }
    return usernames;
}

三、异常处理机制

3.1 异常体系结构

Java异常体系:

异常分类

  1. 编译时异常:必须显式处理(如IOException)
  2. 运行时异常:可处理也可不处理(如NullPointerException)

3.2 异常处理方式

抛出异常(throws)
java 复制代码
public void readFile() throws IOException {
    // 可能抛出IOException的代码
    FileReader reader = new FileReader("file.txt");
    // ...
}

alt+回车 跑出异常

捕获异常(try-catch)
java 复制代码
try {
    // 可能出错的代码
    int result = 10 / 0;
} catch (ArithmeticException e) {
    // 处理算术异常
    System.out.println("除数不能为零");
    e.printStackTrace();
} catch (Exception e) {
    // 处理其他异常
    System.out.println("发生未知错误");
} finally {
    // 无论是否异常都会执行
    System.out.println("清理资源");
}

3.3 自定义异常

自定义编译时异常

java 复制代码
public class InvalidAgeException extends Exception {
    public InvalidAgeException() {
        super("年龄无效");
    }
    
    public InvalidAgeException(String message) {
        super(message);
    }
}

自定义运行时异常

java 复制代码
public class BusinessException extends RuntimeException {
    public BusinessException(String message) {
        super(message);
    }
}

使用自定义异常

java 复制代码
public void setAge(int age) throws InvalidAgeException {
    if (age < 0 || age > 150) {
        throw new InvalidAgeException("年龄必须在0-150之间");
    }
    this.age = age;
}

3.4 异常处理最佳实践

上图表示A调用B,B调用C,处理异常时,C抛出异常给B,B抛出异常给A,A是最上层,不能再抛, 需要处理,处理方法有两种:(1)记录异常反馈给用户,(2)尝试重新修复

  1. 优先处理具体异常:先捕获具体异常,再捕获通用异常
  2. 避免空catch块:至少记录异常信息
  3. 使用finally释放资源:确保资源正确关闭
  4. 异常信息清晰:提供足够的问题描述
  5. 合理使用自定义异常:封装业务相关异常
  6. 异常与返回码结合:根据场景选择合适方式
java 复制代码
// 标准异常处理模板
public void processFile(String path) {
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(path);
        // 处理文件
    } catch (FileNotFoundException e) {
        log.error("文件不存在: {}", path);
        throw new BusinessException("文件不存在");
    } catch (IOException e) {
        log.error("文件读取错误", e);
        throw new BusinessException("文件处理失败");
    } finally {
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e) {
                log.warn("关闭文件流失败", e);
            }
        }
    }
}

四、总结与应用场景

4.1 算法应用场景

  1. 冒泡/选择排序:小型数据集排序
  2. 二分查找:有序数据集快速查找
  3. 复杂算法:大型系统性能优化

4.2 正则表达式应用场景

  1. 表单验证:手机号、邮箱、身份证号等
  2. 日志分析:提取关键信息
  3. 文本处理:批量替换、格式转换
  4. 数据清洗:去除无效字符

4.3 异常处理应用场景

  1. 资源管理:文件、网络连接等
  2. 业务校验:参数检查、状态验证
  3. 系统边界:第三方服务调用
  4. 错误恢复:事务回滚、重试机制

综合最佳实践

  • 对用户输入使用正则验证
  • 核心业务逻辑使用自定义异常
  • 数据处理结合合适算法
  • 资源操作使用try-with-resources
java 复制代码
// 综合应用示例:用户注册
public void registerUser(String username, String phone, String email) 
        throws InvalidInputException {
    // 正则验证输入
    if (!validatePhone(phone)) {
        throw new InvalidInputException("手机号格式错误");
    }
    if (!validateEmail(email)) {
        throw new InvalidInputException("邮箱格式错误");
    }
    
    // 使用高效算法检查用户名是否已存在
    if (binarySearch(existingUsers, username) >= 0) {
        throw new BusinessException("用户名已存在");
    }
    
    // 保存用户(数据库操作)
    try {
        userDao.save(new User(username, phone, email));
    } catch (SQLException e) {
        throw new PersistenceException("用户保存失败", e);
    }
}

掌握这些核心技术,能够显著提升代码质量和开发效率。在实际项目中,合理组合使用算法、正则和异常处理,可以构建出健壮高效的Java应用程序。

相关推荐
随缘而动,随遇而安43 分钟前
第八十八篇 大数据中的递归算法:从俄罗斯套娃到分布式计算的奇妙之旅
大数据·数据结构·算法
IT古董1 小时前
【第二章:机器学习与神经网络概述】03.类算法理论与实践-(3)决策树分类器
神经网络·算法·机器学习
Fireworkitte3 小时前
Apache POI 详解 - Java 操作 Excel/Word/PPT
java·apache·excel
weixin-a153003083163 小时前
【playwright篇】教程(十七)[html元素知识]
java·前端·html
DCTANT4 小时前
【原创】国产化适配-全量迁移MySQL数据到OpenGauss数据库
java·数据库·spring boot·mysql·opengauss
Touper.4 小时前
SpringBoot -- 自动配置原理
java·spring boot·后端
黄雪超4 小时前
JVM——函数式语法糖:如何使用Function、Stream来编写函数式程序?
java·开发语言·jvm
ThetaarSofVenice4 小时前
对象的finalization机制Test
java·开发语言·jvm
水木兰亭4 小时前
数据结构之——树及树的存储
数据结构·c++·学习·算法
Jess075 小时前
插入排序的简单介绍
数据结构·算法·排序算法