【Java从入门到大牛】常见算法、正则表达式、异常

本文由 程序喵正在路上 原创,CSDN首发!
系列专栏:Java从入门到大牛
首发时间:2023年7月27日
欢迎关注点赞收藏留言
一以贯之的努力 不得懈怠的人生

目录

  • 常见算法
    • 简单认识算法
    • 排序算法
      • 冒泡排序
      • 选择排序
    • 查找算法
      • 二分查找
  • 正则表达式
    • 概述、初体验
    • 书写规则
    • 应用案例
    • 用于查找信息
    • 用于搜索替换、分割内容
  • 异常
    • 认识异常
    • 自定义异常
    • 异常的处理

常见算法

简单认识算法

什么是算法?

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

为什么要学习算法?

可以锻炼我们的编程思维

排序算法

什么是排序 ?

将一组数据按照升序或降序的方式排列

冒泡排序

什么是冒泡排序?

每次从数组中找出最大值放在数组的后面去

实现冒泡排序的关键步骤

  • 确定总共需要做几轮:数组的长度 - 1
  • 每轮比较几次:数组的长度 - i - 1,其中 i 表示第几轮,从 0 开始算
    【Java从入门到大牛】常见算法、正则表达式、异常_第1张图片
  • 当前一个位置大于后一个位置则交换数据
    【Java从入门到大牛】常见算法、正则表达式、异常_第2张图片

代码实现

import java.util.Arrays;

public class Test1 {
    public static void main(String[] args) {
        // 1、准备一个数组
        int[] arr = {5, 1, 3, 2};

        // 2、定义一个循环控制排几轮
        for (int i = 0; i < arr.length - 1; i++) {
            // 3、定义一个循环控制每轮比较几次
            for (int j = 0; j < arr.length - i - 1; j++) {
                // 判断当前位置的元素值,是否大于后一个位置处的元素值,如果大则交换
                if(arr[j] > arr[j+1]){
                    int temp = arr[j + 1];
                    arr[j + 1] = arr[j];
                    arr[j] = temp;
                }
            }
        }

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

选择排序

什么是选择排序?

每轮选择当前位置,开始找出后面的较小值与该位置交换

选择排序的关键步骤

  • 确定总共需要选择几轮:数组的长度 - 1
  • 控制每轮从当前位置为基准,与后面元素选择几次
    【Java从入门到大牛】常见算法、正则表达式、异常_第3张图片

代码实现

import java.util.Arrays;

public class Test2 {
    public static void main(String[] args) {
        // 1、准备好一个数组
        int[] arr = {5, 1, 3, 2};

        // 2、控制选择几轮
        for (int i = 0; i < arr.length - 1; i++) {
            // i = 0 第一轮    j = 1 2 3
            // i = 1 第二轮    j = 2 3
            // i = 2 第三轮    j = 3
            // 3、控制每轮选择几次
            for (int j = i + 1; j < arr.length; j++) {
                // 判断当前位置是否大于后面位置处的元素值,若大于则交换
                if(arr[i] > arr[j]){
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        
        System.out.println(Arrays.toString(arr));
    }
}

查找算法

最简单的查找算法是顺序查找,也就是从左往右一个一个地找,数据量比较小时效果还行。但是在数据量特别大的时候,这种方式的性能就会很差

二分查找

  • 二分查找,也叫做折半查找
  • 前提条件:数组中的数据必须是有序的
  • 核心思想:每次排除一半的数据,查询数据的性能明显提高很多
  • 二分查找正常的折半条件应该是开始位置 left <= 结束位置 right

二分查找的实现步骤

  • 定义变量记录左边和右边位置
  • 使用 while 循环控制二分查询,条件是左边位置 <= 右边位置
  • 循环内部获取中间元素索引
  • 判断当前要找的元素如果大于中间元素,则左边位置 = 中间索引 + 1
  • 判断当前要找的元素如果小于中间元素,则右边位置 = 中间索引 - 1
  • 判断当前要找的元素如果等于中间元素,则返回当前中间元素索引

二分查找的代码实现

import java.util.Arrays;

public class Test3 {
    public static void main(String[] args) {
        // 1、准备好一个数组
        int[] arr = {7, 23, 79, 81, 103, 127, 131, 147};

        System.out.println(binarySearch(arr, 150));
        System.out.println(Arrays.binarySearch(arr, 81));
    }

    public static int binarySearch(int[] arr, int data){
        // 1、定义两个变量,一个站在左边位置,一个站在右边位置
        int left = 0;
        int right = arr.length - 1;

        // 2、定义一个循环控制折半
        while (left <= right){
            // 3、每次折半,都算出中间位置处的索引
            int middle = (left + right) / 2;
            // 4、判断当前要找的元素值,与中间位置处的元素值的大小情况
            if(data < arr[middle]){
                // 往左边找,截止位置(右边位置) = 中间位置 - 1
                right = middle - 1;
            }else if(data > arr[middle]){
                // 往右边找,起始位置(左边位置) = 中间位置 + 1
                left = middle + 1;
            }else {
                // 中间位置处的元素值,正好等于我们要找的元素值
                return middle;
            }
        }
        
        return -1; // -1特殊结果,就代表没有找到数据!数组中不存在该数据!
    }
}

正则表达式

概述、初体验

什么是正则表达式?

就是由一些特定的字符组成,代表的是一个规则

正则表达式的作用

  1. 用来校验数据格式是否正确
  2. 用来在一段文本中查找满足要求的内容

初体验:检验QQ号是否合法

/**
 * 目标:体验一下使用正则表达式来校验数据格式的合法性。
 * 需求:校验QQ号码是否正确,要求全部是数字,长度是(6-20)之间,不能以0开头。
 */
public class RegexTest1 {
    public static void main(String[] args) {
        // 普通方法
        System.out.println(checkQQ(null));
        System.out.println(checkQQ("251425876"));
        System.out.println(checkQQ("2514a8d76"));
        System.out.println("--------------------------------------------------");

        // 正则表达式
        System.out.println(checkQQ1(null));
        System.out.println(checkQQ1("251425876"));
        System.out.println(checkQQ1("2514a8d76"));

    }

    // 正则表达式
    public static boolean checkQQ1(String qq){
        return qq != null && qq.matches("[1-9]\\d{5,19}");
    }

    // 普通方法
    public static boolean checkQQ(String qq){
        // 1、判断qq号码是否为null
        if(qq == null || qq.startsWith("0") || qq.length() < 6 || qq.length() > 20){
            return false;
        }

        // 2、qq至少是不是null,不是以0开头的,满足6-20之间的长度
        // 判断qq号码中是否都是数字
        for (int i = 0; i < qq.length(); i++) {
            // 根据索引提取当前位置处的字符
            char ch = qq.charAt(i);
            // 判断ch记住的字符,如果不是数字,qq号码不合法
            if(ch < '0' || ch > '9'){
                return false;
            }
        }
        
        // 3、说明qq号码肯定是合法
        return true;
    }
}

在IDEA里快速书写for循环的方法

  1. 敲出 i 的范围加上 .fori 或者 .forr
    【Java从入门到大牛】常见算法、正则表达式、异常_第4张图片
  2. 然后回车
    【Java从入门到大牛】常见算法、正则表达式、异常_第5张图片

上面代码中的 for 循环的快速生成代码为 qq.length().fori

书写规则

String提供了一个匹配正则表达式的方法

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

正则表达式的书写规则

【Java从入门到大牛】常见算法、正则表达式、异常_第6张图片

【Java从入门到大牛】常见算法、正则表达式、异常_第7张图片

具体使用演示

由于在 Java 中,反斜杠是有特殊意义的,所以在使用 \d 等规则时,我们需要在前面加一个反斜杠来进行转义

/**
 * 目标:掌握正则表达式的书写规则
 */
public class RegexTest2 {
    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,除了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)+"));
    }
}

应用案例

需求

校验用户输入的电话、邮箱是否合法

代码示例

import java.util.Scanner;

/**
 * 目标:校验用户输入的电话、邮箱、时间是否合法
 */
public class RegexTest3 {
    public static void main(String[] args) {
        // checkPhone();
        checkEmail();
    }

    public static void checkPhone(){
        while (true) {
            System.out.println("请您输入您的电话号码(手机|座机): ");
            Scanner sc = new Scanner(System.in);
            String phone = sc.nextLine();
            // 18676769999  010-3424242424 0104644535
            if(phone.matches("(1[3-9]\\d{9})|(0\\d{2,7}-?[1-9]\\d{4,19})")){
                System.out.println("您输入的号码格式正确~~~");
                break;
            }else {
                System.out.println("您输入的号码格式不正确~~~");
            }
        }
    }

    public static void checkEmail(){
        while (true) {
            System.out.println("请您输入您的邮箱: ");
            Scanner sc = new Scanner(System.in);
            String email = sc.nextLine();
            /**
             * [email protected]
             * [email protected]
             */
            if(email.matches("\\w{2,}@\\w{2,20}(\\.\\w{2,10}){1,2}")){
                System.out.println("您输入的邮箱格式正确~~~");
                break;
            }else {
                System.out.println("您输入的邮箱格式不正确~~~");
            }
        }
    }
}

用于查找信息

案例:使用正则表达式查找一段文本中的内容

需求1:请把下面文本中的电话、邮箱、座机号码、热线都爬取出来

电话:18512516758,18512508907
或者联系邮箱: [email protected]
座机电话:01036517895,010-98951256
邮箱:[email protected]
邮箱2:[email protected]
热线电话:400-618-9090 ,400-618-4000,
4006184000,4006189090

需求1代码示例

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 目标:掌握使用正则表达式查找内容。
 */
public class RegexTest4 {
    public static void main(String[] args) {
        method1();
    }

    // 需求 1:从以下内容中爬取出手机,邮箱,座机、400电话等信息
    public static void method1(){
        String data = "      电话:1866668888,18699997777\n" +
                    "        或者联系邮箱:[email protected],\n" +
                    "        座机电话:01036517895,010-98951256\n" +
                    "        邮箱:[email protected],\n" +
                    "        邮箱:[email protected],\n" +
                    "        热线电话:400-618-9090 ,400-618-4000,4006184000,4006189090";

        // 1、定义爬取规则
        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);
        }
    }
}

【Java从入门到大牛】常见算法、正则表达式、异常_第8张图片

需求2:只需要把每个邮箱中的用户名爬取出来

电话:18512516758,18512508907
或者联系邮箱: [email protected]
座机电话:01036517895,010-98951256
邮箱:[email protected]
邮箱2:[email protected]
热线电话:400-618-9090 ,400-618-4000,
4006184000,4006189090

需求3:某系统的日志文件记录了当天进入系统的全部用户信息,现在需要将这些用户的名字爬取出来另作他用

欢迎张全蛋光临本系统!他删库并跑路
欢迎李二狗子光临本系统!
欢迎马六子光临本系统!它浏览了很多好看的照片!
欢迎夏洛光临本系统!他在六点钟送出了一个嘉年华

需求2、3代码示例

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexTest5 {
    public static void main(String[] args) {
        method1();
        method2();
    }

    // 需求2:把全部邮箱的账户名找出来
    public static void method1(){
        String data = " 来黑马程序员学习Java,\n" +
                "        电话:1866668888,18699997777\n" +
                "        或者联系邮箱:[email protected],\n" +
                "        座机电话:01036517895,010-98951256\n" +
                "        邮箱:[email protected],\n" +
                "        邮箱:[email protected],\n" +
                "        热线电话:400-618-9090 ,heima, 400-618-4000,4006184000,4006189090";
        // 1、定义爬取规则
        String regex = "(\\w{2,})@(\\w{2,20})(\\.\\w{2,10}){1,2}";
        // 2、把正则表达式封装成一个Pattern对象
        Pattern pattern = Pattern.compile(regex);
        // 3、通过pattern对象去获取查找内容的匹配器对象。
        Matcher matcher = pattern.matcher(data);
        // 4、定义一个循环开始爬取信息
        while (matcher.find()){
            System.out.println(matcher.group());
            System.out.println(matcher.group(1)); // 指定获取正则表达式匹配后的第一组内容
            System.out.println(matcher.group(2)); // 指定获取正则表达式匹配后的第二组内容
            System.out.println(matcher.group(3));
        }
    }


    // 需求3:某系统的日志文件记录了当天进入系统的全部用户信息,需要把这些用户的名字爬取出来另作他用。
    public static void method2(){
        String data = "欢迎张全蛋光临本系统!他删库并跑路,欢迎李二狗子光临本系统!" +
                "欢迎马六子光临本系统!它浏览了很多好看的照片!欢迎夏洛光临本系统!他在六点钟购买了一台拖拉机!";
        // 1、定义爬取规则
        // String regex = "欢迎(.+)光临"; // 贪婪匹配
        String regex = "欢迎(.+?)光临"; // +? 非贪婪匹配
        // 2、把正则表达式封装成一个Pattern对象
        Pattern pattern = Pattern.compile(regex);
        // 3、通过pattern对象去获取查找内容的匹配器对象。
        Matcher matcher = pattern.matcher(data);
        // 4、定义一个循环开始爬取信息
        while (matcher.find()){
            System.out.println(matcher.group());
            System.out.println(matcher.group(1));
        }
    }
}

【Java从入门到大牛】常见算法、正则表达式、异常_第9张图片

用于搜索替换、分割内容

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

方法名 说明
public String replaceAll(String regex, String newStr) 按照正则表达式匹配的内容进行替换
public String[] split(String regex) 按照正则表达式匹配的内容进行分割字符串,返回一个字符串数组

实际应用

import java.util.Arrays;

/**
 * 目标:掌握使用正则表达式做搜索替换,内容分割
 */
public class RegexTest6 {
    public static void main(String[] args) {
        // 1、public String replaceAll(String regex , String newStr):按照正则表达式匹配的内容进行替换
        // 需求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"));

        // 2、public String[] split(String regex):按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。
        // 需求1:请把 古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴,中的人名获取出来。
        String s3 = "古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
        String[] names = s3.split("\\w+");
        System.out.println(Arrays.toString(names));
    }
}

【Java从入门到大牛】常见算法、正则表达式、异常_第10张图片

异常

认识异常

什么是异常 ?

异常就是代表程序出现的问题

异常的体系

【Java从入门到大牛】常见算法、正则表达式、异常_第11张图片

Error:代表的是系统级别错误(属于严重问题),也就是说系统一旦出现问题,sun 公司会把这些问题封装成 Error 对象表示出来,说白了,Error 是给 sun 公司自己用的,不是给我们程序员用的,因此开发人员不用管

Exception:叫异常,它代表的才是我们程序出现的问题,所以,我们程序员通常会用 Exception 以及它的子类来封装程序出现的问题

  • 运行时异常:RuntimeException 及其子类,编译阶段不会出现错误提醒,运行时出现的异常,如:数字索引越界异常
  • 编译时异常,编译阶段就会出现错误提醒的,如:日期解析异常

抛出异常

在方法上使用 throws 关键字,可以将方法内部出现的异常抛出去给调用者处理

方法 throws 异常1, 异常2, 异常3... {
	...
}

捕获异常(try…catch)

直接捕获程序出现的异常

try {
	// 监视可能出现异常的代码 
} catch(异常类型1 变量) {
	// 处理异常
} catch(异常类型2 变量) {
	// 处理异常
}...

自定义异常

什么是自定义异常 ?

Java 无法为这个世界上全部的问题都提供异常类来代表,如果企业自己的某种问题,想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了

自定义异常的种类

自定义运行时异常

  • 定义一个异常类继承 RuntimeException
  • 重写构造器
  • 通过 throw new 异常类(xxx) 来创建异常对象并抛出

自定义编译时异常

  • 定义一个异常类继承 Exception
  • 重写构造器
  • 通过 throw new 异常类(xxx) 来创建异常对象并抛出

异常有什么作用 ?

  1. 异常是用来查询系统 Bug 的关键参考信息
  2. 异常可以作为方法内部的一种特殊返回值,以便通知上层调用者底层的执行情况

异常的处理

开发中对于异常的常见处理方式

  1. 捕获异常,记录异常并响应合适的信息给用户
  2. 捕获异常,尝试重新修复

抛出异常

在方法上使用 throws 关键字,可以将方法内部出现的异常抛出去给调用者处理

// 推荐方式
方法 throws Exception {
}
// Exception代表可以捕获一切异常

捕获异常(try…catch)

直接捕获程序出现的异常

// 推荐方式
try {
	// 监视可能出现异常的代码 
} catch(Exception e) {
	e.printStackTrace();	// 直接打印异常对象的信息
} 
// Exception代表可以捕获一切异常

你可能感兴趣的:(Java从入门到大牛,算法,java,正则表达式)