面向对象-异常&Lambda&算法&正则

(1)异常

代表程序出现的问题

  • 异常体系
        Throwable
      Error 代表的系统级别错误 (属于严重问题),Error是给sun公司自己用的,我们了解即可
      Exception 代表异常,程序可能出现的问题,我们通常会用Exception以及它的子类来封装程序出现的问题
      RuntimeException 运行时异常(非受检异常),例如数组索引越界、空指针、数学运算异常等
      其他Exception    编译时异常(受检异常),例如解析异常
  • JVM默认处理是常的方式
        1. 打印异常信息
        2. 立即结束程序(异常出现后,如果不处理,程序是无法继续向下运行的)
    
    
public class Demo1 {
    public static void main(String[] args){
        //1. 运行时异常(非受检异常),例如数组索引越界、空指针、数学运算异常等
        //1-1 数组索引越界
        int[] arr = {29,38,11};
        // System.out.println(arr[3]);
        //1-2 空指针
        String str = null;
        System.out.println(str.length());
        //1-3 数学运算
        int i =1/0;
        System.out.println(i);
        //2. 编译时异常(受检异常),例如解析异常
        //日期格式解析异常
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        
        try {
            sdf.parse("2019");
        } catch (ParseException e) {
            e.printStackTrace();
        }
        System.out.println("程序继续向下运行");
        


    }
}
  • 异常处理的方案1--抛异常
        在Java的方法调用中,如果一个方法中出现了异常,本方法自己不处理,默认是会抛给调用方法去处理的
        此时要注意的是,如果发生的是非运行时异常,需要在方法上明确使用throws关键字声明抛出
    
  • 格式
        public void 方法名 throws 异常1 ,异常2 ,异常3 ..{
            方法体
            throw new Exception()
public class Demo2 {

    public static void main(String[] args) throws ParseException {
        int []arr = {1,2,3};
        System.out.println(arr[5]);

        String str = null;
        //System.out.println(str.length());

        new SimpleDateFormat("yyyy-MM-dd").parse("2019-09-09");

 
    }
}
  • 处理的方案2--捕获异常
        直接在当前方法,发生异常的代码外使用try--catch--结构捕获并处理异常
        异常处理后,后续的代码是可以继续执行的
  • 格式
        public void 方法名{
            try{
                // 方法体
            }catch(异常类型1 变量){
                // 处理异常
            }catch(异常类型2 变量){
                // 处理异常
            }
        }
public class Demo3 {
    public static void main(String[] args) {
        print();
    }
    public static void print(){
        //1.运行时异常
        String srt = null;
        //System.out.println("字符串长度:" + srt.length());

        try {
            //java代码,jdk会监控try中的代码,一旦出现指定类型的错误,会进入到catch中做容错处理
            System.out.println("字符串长度:" + srt.length());
            new SimpleDateFormat("yyyy-MM-dd").parse("2019");
        }catch (Exception e){
            e.printStackTrace();//打印堆栈异常信息
            System.out.println("字符串为空,长度为0");
        }

    }
}
  • 自定义异常
        Java无法为这个世界上全部的问题都提供异常类来代表,如果以后我们自己写的代码中的某种问题,
        想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了。
  • 自定义运行时异常
        1、定义一个异常类,继承RuntimeException
        2、在类中提供构造函数
        3、在需要抛出异常的地方使用throw关键字 抛出异常类的对象
  • public class Demo4 {
         public static void main(String[] args) {
            //模拟用户登录,用户名:admin,密码123456
             System.out.println(login("admin","123456"));
        }
    
        //设置登录的方法
        public static String login(String username,String password) {
    
            if (!username.equals("admin")) {
                //1.用户名错误,用户登录失败
                throw new LoginException("用户名错误,用户登录失败");
            } else if (!password.equals("123456")) {
                //2.用户密码错误,用户登录失败
                throw new LoginException("用户密码错误,用户登录失败");
            } else {
                //3.用户登录成功,返回用户信息
                return "用户登录成功,用户名" + username;
            }
    
        }
    
    }
    
    //自定义运行时异常类
    class LoginException extends RuntimeException{
        //有参构造
        public LoginException(String message) {
            super(message);
        }
    }
    
  • 自定义异常
        Java无法为这个世界上全部的问题都提供异常类来代表, 如果以后我们自己写的代码中的某种问题,
        想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了。
  • 自定义编译时异常
        1、定义一个异常类,继承Exception
        2、在类中提供构造函数
        3、在需要抛出异常的地方使用throw关键字 抛出异常类的对象
  • 注意
        编译时异常,在编写代码的过程中必须手动处理
  • 异常的作用
        1、异常是用来查找系统bug 的关键参考信息
        2、异常可以作为方法内部一种特殊的返回值,以便通知上层调用者,代码底层的执行情况
    
public class Demo5 {
    public static void main(String[] args) throws LoginException2{
        //模拟用户登录,用户名:admin,密码123456
        System.out.println(login("admin","1023456"));
    }

    //设置登录的方法
    public static String login(String username,String password) throws LoginException2 {

        if (!username.equals("admin")) {
            //1.用户名错误,用户登录失败
            throw new LoginException2("用户名错误,用户登录失败");
        }else if (!password.equals("123456")) {
            //2.用户密码错误,用户登录失败
            throw new LoginException2("用户密码错误,用户登录失败");
        }else {
            //3.用户登录成功,返回用户信息
            return "用户登录成功,用户名" + username;
        }
    }

}

//自定义编译时异常类
class LoginException2 extends Exception {
    public LoginException2(String message) {
        super(message);
    }
}
(2)Lambda
  • Lambda表达式
        是JDK8开始新增的一种语法形式,主要用来简化匿名内部类代码的书写
  • Lambda格式
        (被重写方法的参数列表)->{
            被重写方法的方法体;
        }
  • Lambda使用前提
        Lambda只能操作函数式接口(有且仅有一个抽象方法的接口,被FunctionalInterface注解修饰)
    
public class Demo1 {
    public static void main(String[] args) {
        //匿名内部类操作接口
        Person person = new Person() {
            @Override
            public void eat() {
                System.out.println("吃饭");
            }
        };
        person.eat();
        //Lambda简化
        Person person1 = () -> {
                System.out.println("吃软饭");};
        person1.eat();
        System.out.println("===========================================");

        //匿名内部类操作抽象类
        Animal animal = new Animal() {
            @Override
            void eat() {
                System.out.println("狗吃肉脯");
            }
        };//无法使用Lambda简化
        animal.eat();


    }

}


//接口
interface Person {
    void eat();
}

//抽象类
abstract class Animal {
    abstract void eat();
}
public class Demo2 {
    public static void main(String[] args) {
        //调用test方法,最后打印乌鸦喝水
        Bird bird = () -> System.out.println("乌鸦喝水");
        bird.drink();
    }
}

interface Bird {
    //无参数无返回值
    void drink();
}
public class Demo3 {

    public static void main(String[] args) {
        //调用test方法, 最后显示  哈哈哈哈
        test( info -> System.out.println(info));
    }

    public static void test(Printer printer) {
        printer.fun("哈哈哈哈");
    }
}

interface Printer {
    void fun(String info);
}
public class Demo4 {

    public static void main(String[] args) {
        //调用test完成 a+b  的计算
        test((a,b) ->  a+b);
    }

    public static void test(Calculator calculator) {
        System.out.println("运算结果:" + calculator.add(10, 20));
    }
}


interface Calculator {
    int add(int a, int b);
}
(3)方法引用
  • JDK8新特性,方法引用
        主要用来简化、替换Lambda表达式
  • 方法引用分类
        1、静态方法的引用
        2、实例方法的引用
        3、特定类型方法的引用
        4、构造器引用
  • 小提示
        先写匿名内部类,发现能化再化(写的多了就热练了)
    
  • 1、静态方法的引用:
        某个Lambda只是调用一个静态方法,并且前后参数一致,即可使用  类名::静态方法
    
    2、实例方法的引用:
        某个Lambda只是调用一个实例方法,并且前后参数一致,即可使用  对象名::实例方法
  • public class Demo1 {
        public static void main(String[] args) {
            Student[] students = new Student[4];
            students[0] = new Student("蜘蛛精", 169.5, 23);
            students[1] = new Student("紫霞", 163.8, 26);
            students[2] = new Student("紫霞", 163.8, 27);
            students[3] = new Student("至尊宝", 167.5, 24);
    
            //1、 使用匿名内部类完成按照年龄排序功能
    //        Arrays.sort(students, new Comparator<Student>() {
    //            @Override
    //            public int compare(Student o1, Student o2) {
    //                return MyComparator.compareByAge1(o1, o2);
    //            }
    //        });
            //2、 使用Lambda完成按照年龄排序功能
    //        Arrays.sort(students, (Student o1, Student o2) -> {
    //                return MyComparator.compareByAge1(o1, o2);
    //            });
            //3、 将升序排列的逻辑,封装到一个静态方法中, 调用完成
                 //1- 内部类中方法。调用其他的静态方法
                 //2- 调用静态方法时,参数列表和内部类方法参数列表顺序一致
                 //3- 工具类 :: 方法名
    //        Arrays.sort(students,MyComparator :: compareByAge1);
            //4、 将升序排列的逻辑,封装到一个实例方法中, 调用完成
                //1- 内部类中方法。调用其他的实例方法
                //2- 调用静态方法时,参数列表和内部类方法参数列表顺序一致
                //3- new 对象() :: 方法名
            Arrays.sort(students, new MyComparator() :: compareByAge2);
            //打印效果
            System.out.println(Arrays.toString(students));
        }
    }
    
    
    class Student {
        private String name;
        private double height;
        private int 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 double getHeight() {
            return height;
        }
    
        public void setHeight(double height) {
            this.height = height;
        }
    
        public Student(String name, double height, int age) {
            this.name = name;
            this.height = height;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", height=" + height +
                    ", age=" + age +
                    '}';
        }
    }
    class MyComparator {
        public static int compareByAge1(Student s1, Student s2) {
            return s1.getAge() > s2.getAge() ? 1 : -1;
        }
    
        public  int compareByAge2(Student s1, Student s2) {
            return s1.getAge() > s2.getAge() ? 1 : -1;
        }
    }
    3、特定类型方法的引用:
        如果某个Lambda只是调用一个实例方法,并且前面参数列表中第一个参数作为主调,后面的参数作为入参,即可使用  类型::方法
    
    借助string类的compareToIgnoreCase方法,忽略大小写比较字符内容
public class Demo2 {
    public static void main(String[] args) {
        String[] names = {"boby", "angela", "Andy", "dlei", "caocao", "Babo", "jack", "Cici"};

        //1、使用匿名内部类对数组进行排序,规则是忽略大小写进行排序(String int compareToIgnoreCase(String str))
        Arrays.sort(names, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareToIgnoreCase(o2);
            }
        });
        System.out.println(Arrays.toString(names));
        //2、 Lambda简化上述代码
        Arrays.sort(names, (String o1, String o2) -> {
                return o1.compareToIgnoreCase(o2);
            });
        System.out.println(Arrays.toString(names));
        //3、使用特定类型方法的引用  简化Lambda代码
        // 类型 :: 方法
        Arrays.sort(names, String::compareToIgnoreCase);
        //打印结果
        System.out.println(Arrays.toString(names));

    }
}
4、构造器引用
    如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用   类名::new
public class Demo3 {
    public static void main(String[] args) {
        CreateCar createCar = null;

        //1. 使用匿名内部类方式调用CreateCar实现对象的创建
//        createCar = new CreateCar() {
//            @Override
//            public Car create(String brand, double price) {
//                return new Car(brand, price);
//            }
//        };

        //2. 使用Lambda优化上面代码
        //createCar = ( brand,  price) -> new Car(brand, price);

        //3. 构造器引用  类名::new
        createCar = Car::new;
        //对象打印
        System.out.println(createCar.create("宝马", 100000));
    }

}

//接口功能: 完成Car对象的创建
interface CreateCar {
    Car create(String brand, double price);
}

class Car {
    private String brand;
    private double price;

    public Car(String brand, double price) {
        this.brand = brand;
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", price=" + price +
                '}';
    }
}
(4)常见算法
  • 冒泡排序
        相邻的两个元素进行比较,小的放左边大的放右边,完成升序排列
    
  • 实现步骤
        确定总共需要做几轮: 数组长度-1
        每轮比较几次: 轮数从0计数的话, 就是数组长度-1-当前轮数
        比较规则: 相邻两个元素比较,大的放在右边
public class Demo1 {
    public static void main(String[] args) {
        int[] arr = {5, 2, 3, 1,10, 8, 9, 7, 6};
        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void bubbleSort(int[] arr) {
        // 控制轮数:确定总共需要做几轮: 数组长度-1
        for (int i = 0; i < arr.length-1 ; i++) {
            // 每轮比较几次: 轮数从0计数的话, 就是数组长度-1-当前轮数
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if(arr[j] > arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }
}
  • 选择排序
        每轮选择当前位置,开始找后面的最小值,与当前位置交换
  • 关键点分析
        确定总共需要做几轮: 数组长度-1
        每次的基准位:轮数从0计数的话, 就是基准位索引敲好就是轮数
        比较规则: 以每次的第一个为基准做比较,谁小谁来基准位
public class Demo2 {
    public static void main(String[] args) {
        int[] arr = {5, 2, 3, 1};
        selectionSort(arr);
        System.out.println(Arrays.toString(arr));
    }


    private static void selectionSort(int[] arr) {
        // 控制轮数:确定总共需要做几轮: 数组长度-1
        for (int i = 0; i < arr.length-1; i++) {
            // 每次的基准位:轮数从0计数的话, 就是基准位索引恰好就是轮数(i+1)
            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;
                }
            }
        }
    }
}
  • 二分查找/折半查找
        前提是数组有序
        特点是每一次查找完成,会舍去一半元素
  • 思路分析
        1、定义两个指针,指向数组第一个和最后一个索引位置
        2、循环查找,min小于等max则继续(三个指针可能重叠的)
        3、每次循环进来,重新计算中间指针
        4、判断情况1:如果mid指向的元素就是num,则返回mid
        5、判断情况2:如果要查找的元素,在左半边,舍弃max重新计算
        6、判断情况3:如果要查找的元素,在右半边,舍弃min重新计算
        7、循环结束没有找到,则代表不存在,返回-1
public class Demo1 {
    public static void main(String[] args) {
        int[] arr = {10, 23, 39, 45, 59, 166, 728, 810, 999};

        System.out.println("索引位置为:" + binarySearch(arr, 166));
        System.out.println("索引位置为:" + binarySearch(arr, 200));

    }

    //二分查找
    private static int binarySearch(int[] arr, int num) {
        //1.设置返回索引
        int index = -1;
        //2.设置开始和结束索引
        int min = 0;
        int max = arr.length - 1;
        //3.使用while循环,条件:左侧开始索引 <= 右侧结束索引
        while (min<=max){
            //4.计算中间索引
            int mid = (min + max)/2;
            //5.使用中间索引的数据和需要查询的num比较
            //5.1 数据一致,返回索引位置
            if(num == arr[mid]){
                index = mid;
                break;
            }else if(num < arr[mid]){
                //5.2 数据小于中间索引的数据,舍弃右侧数据,重新计算
                max = mid - 1;
            }else{
                //5.3 数据大于中间索引的数据,舍弃左侧数据,重新计算
                min = mid + 1;
            }
        }
        //如果min>max,则代表没有找到,返回-1
        //6.循环结束,返回索引位置
        return index;
    }
}
(5)正则表达式
  • 用法
        boolean  待校验字符串.matches("正则规则")
    
public class Demo1{
    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(checkQQWithRegex(null));
        System.out.println(checkQQWithRegex("251425876"));
        System.out.println(checkQQWithRegex("2514a8d76"));

    }

    //不用正则校验QQ号(qq至少是不是null,不是以0开头的,满足6-20之间的长度)
    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号码中是否都是数字。
        // qq = 2514ghd234
        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;
    }

    //使用正则校验QQ号(qq至少是不是null,不是以0开头的,满足6-20之间的长度)
    public static boolean checkQQWithRegex(String qq){
        return qq != null && qq.matches("[1-9]\\d{5,19}");
    }
}

  • 语法
        1、替换
            替换后字符串   源字符串.replaceAll(正则规则, 待替换串)
    
        2、分割
            分割后数组   源字符串.split(正则规则)
public class Demo2 {
    public static void main(String[] args) {
        // 需求1:请把下面文字中的非中文字符替换成-
        String s1 = "古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
        System.out.println(s1.replaceAll("\\w+", "-"));

        // 需求2:请把 下面文字中的人名获取出来
        String s3 = "古力娜扎ai8888迪丽热巴999aa5566马尔扎哈fbbfsfs42425卡尔扎巴";
        String[] names = s3.split("\\w+");
        System.out.println(Arrays.toString(names));
    }
}
  • 语法
        1. 把正则表达式封装成一个Pattern对象
            Pattern pattern = Pattern.compile(regex);
    
        2. 通过pattern对象去获取查找内容的匹配器对象。
            Matcher matcher = pattern.matcher(全文字符串);
    
        3. 遍历查找
            while (matcher.find()){
                String rs = matcher.group();
            }
public class Demo3 {
    public static void main(String[] args) {
        method1();
    }

    // 需求1:从以下内容中爬取出,手机,邮箱,座机、400电话等信息。
    public static void method1(){
        String data = " 来黑马程序员学习Java,\n" +
                "        电话:1866668888,18699997777\n" +
                "        或者联系邮箱:boniu@itcast.cn,\n" +
                "        座机电话:01036517895,010-98951256\n" +
                "        邮箱:bozai@itcast.cn,\n" +
                "        邮箱:dlei0009@163.com,\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);
        }
    }

}
public class Demo4 {
    public static void main(String[] args) {
        // 1、字符类(只能匹配单个字符)
        //[abc]只能匹配a、b、c
        System.out.println("a".matches("[abc]"));  //true
        System.out.println("e".matches("[abcd]")); //false

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

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

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

        //[a-zA-Z0-9] 任意数字和字母
        System.out.println("b".matches("[a-zA-Z0-9]")); //true
        System.out.println("ab".matches("[a-zA-Z0-9]")); //false

        System.out.println("====================================");
        // \转义
        System.out.println("\"");

        // 2、预定义字符(只能匹配单个字符)
        //.可以匹配任意字符
        System.out.println("徐".matches(".")); //true
        System.out.println("徐徐".matches(".")); //false

        //\d: 0-9
        System.out.println("3".matches("\\d"));  //true
        System.out.println("a".matches("\\d"));  //false

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

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

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

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

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

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

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

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

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

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值