五、异常和线程

一、异常

java.lang.

  • Throwable:是所有错误或异常的超类

    • Error:错误

      错误相当于程序得了一个无法治愈的毛病,必须修改源代码

    • Exception编译期异常,进行编译(写代码)java程序出现的问题

      • RuntimeException:运行期异常,java程序运行过程中出现的问题

        异常相当于程序得了一个小毛病,把异常处理掉,程序可以继续执行

JVM检测程序会出现异常

JVM会做两件事:JVM中断处理

  1. JVM根据异常原因创建一个异常对象,包含内容,原因和位置

  2. 如果没有异常处理逻辑(try...catch),JVM就会把异常抛出给方法的调用者main方法

    main接收到这个异常对象,也没有处理逻辑就抛出给main方法的调用者JVM处理

    JVM接收到这个异常对象,做了两件事1. 把异常对象以红色字体打印在控制台 2.终止现在正在执行的java程序

二、异常的处理

2.1 抛出异常throw

throw关键字

作用:

​ 可以使用throw关键字在指定的方法中抛出指定的异常

使用格式:

​ throw new xxxException("异常产生的原因")

注意:

  1. throw关键字必须写在方法内部

  2. throw关键字后边new的对象必须是Exception或者Exception的子类对象

  3. throw关键字抛出指定的异常对象,我们必须处理这个异常对象

    throw关键字后面创建的是RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给JVM处理

    throw关键字后面创建的是编译异常,我们就必须处理这个异常,要么throws要么try...catch

throw new NullPointerException("传递对象为null");

2.2 Objects非空判断

Object obj = null;
Objects.requireNonNull(obj,"传递的对象为null");

2.3 声明异常throws

异常处理的第一种方式,交给别人处理

作用:

​ 当方法内部抛出异常对象的时候,必须处理这个异常对象

​ 可以使用throws处理异常,把异常对象交给调用者处理,JVM-->中断处理

使用格式:在方法声明时使用

​ 修饰符 返回值类型 方法名(参数列表)throws XXXException,...{

​ throw new XXXException("产生原因");

}

注意:

  1. throws关键字必须写在方法声明处

  2. throws关键字后声明的异常必须是Exception或者是Exception的子类

  3. 方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常

    如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可

    1. 调用了一个声明抛出异常的方法,我们就必须处理声明的异常

    要么继续使用throws抛出,交给方法调用者处理,最终交给JVM

    要么try...catch

public class Demo01Throwable {
    public static void main(String[] args) throws IOException {
        readFile("c://a.txt");
    }
    public static void readFile(String fileName) throws IOException {
        if (!fileName.equals("c://a.txt")){
            throw new FileNotFoundException("文件路径异常");
        }

        if (!fileName.endsWith(".txt")){
            throw new IOException("文件的后缀名异常");
        }
    }
}

2.4 捕获异常try catch

try...catch:异常处理的第二种方式,自己处理异常

格式:

​ try{

​ }catch(定义一个异常的变量,用来接收try中抛出的异常对象){

​ 异常的处理逻辑,一般在工作中,会把异常信息记录到一个日志中

​ }

注意:

  1. try中可能会抛出多个异常,可以使用多个catch来处理

  2. 如果try中产生了异常,就会执行catch中的异常处理逻辑,执行完catch中的处理逻辑,就会执行之后的代码

    如果try没有产生异常,就不会执行catch中异常处理逻辑,执行完try中的代码,继续执行try...catch后的代码

public class Demo01Throwable {
    public static void main(String[] args){
        try {
            readFile("c://a.xt");
        } catch (IOException e) {
            System.out.println("catch.文件后缀不是.txt");
        }
        System.out.println("后续代码");
    }
    public static void readFile(String fileName) throws IOException {

        if (!fileName.endsWith(".txt")){
            throw new IOException("文件的后缀名异常");
        }
    }
}

Throwable类中定义了3个异常处理的方法

  • String getMessage() 返回throwable的简短描述

  • String toString() 返回throwable的详细信息字符串

  • void printStackTrace(PrintStream s) JVM打印异常对象,默认此方法,异常信息最全面

2.5 finally代码块

注意:

  1. finally不能单独使用,必须和try一起使用
  2. finally一般用于资源释放,无论程序是否异常,最后都要资源释放(IO)

2.6 多异常捕获处理

  1. 多异常分别处理

  2. 多异常一次捕获,多次处理

    注意事项:

    catch里面定义的异常变量,如果有子父类关系,那么子类异常变量必须写在上边

  3. 多异常一次捕获,一次处理

  • 运行期异常可以不捕获也不处理 交给虚拟机处理
  • finally中有return语句,永远返回finally的结果,避免该情况
  • 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者父类异常的子类或者不抛出异常
  • 父类方法没有抛出异常,子类重写父类方法时,也不能抛出异常,只能捕获处理

三、 自定义异常

自定义异常类:

​ java提供异常类,不够我们使用,需要自己定义一些异常类

格式:

​ public class XXXException extends Exception / RuntimeException{

​ 添加一个空参数的构造方法

​ 添加一个带异常信息的构造方法

}

注意:

1. 自定义异常类一般都是以Exception结尾,说明该类是一个异常类
2. 自定义异常类,必须继承Exception或者RuntimeException
  	1. 继承Exception,那么自定义异常类是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try catch
  	2. 继承RuntimeException,那么自定义异常类是一个运行期异常,无需处理,交给虚拟机处理(中断处理

1.继承Exception

public class MyException extends Exception {
    public MyException(){
        super();
    }
    public MyException(String s){
        super(s);
    }
}
public class Demo01Throwable {
    //1.使用数据保存已经注册的用户名
    static String[] userNames={"张三","李四","王五"};
        //写在成员位置 方便都访问的到
    public static void main(String[] args) /*throws MyException*/ {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入您要注册的用户名:");
        String userName = scanner.next();
        checkUserName(userName);
    }

    public static void checkUserName(String usrname) /*throws MyException*/ {
        for (String userName : userNames) {
            if (usrname.contains(userName)){
                //true
                try {
                    throw new MyException("该用户已经被注册了");
                } catch (MyException e) {
                    e.printStackTrace();
                    return;//结束方法
                }
            }
        }
        System.out.println("恭喜您,注册成功");
    }
}

2.继承RuntimeException

package com.dy.test;

public class MyException extends /*Exception*/ RuntimeException{
    public MyException(){
        super();
    }
    public MyException(String s){
        super(s);
    }
}
public class Demo02Throwable {
    //1.使用数据保存已经注册的用户名
    static String[] userNames={"张三","李四","王五"};
        //写在成员位置 方便都访问的到
    public static void main(String[] args) /*throws MyException*/ {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入您要注册的用户名:");
        String userName = scanner.next();
        checkUserName(userName);
    }

    public static void checkUserName(String usrname) /*throws MyException*/ {
        for (String userName : userNames) {
            if (usrname.contains(userName)){
                //true
                throw new MyException("该用户已经被注册了");//抛出运行期异常 无需处理 交给JVM处理 中断处理
            }
        }
        System.out.println("恭喜您,注册成功");
    }
}

四、多线程

4.1 并发与并行

并发:两个或多个事件在同一时间段内发生。cpu交替执行

并行:两个或多个事件在同一时刻发生(同时发生)。cpu同时执行

4.2 线程与进程

内存:所有应用程序都要进入到内存中执行 临时存储RAM

硬盘:永久存储ROM

点击应用程序执行,进入到内存中,占用一些内存执行,进入到内存的程序叫做进程

任务管理器-->结束进程

那么就把进程从内存中清除了

cpu:中央处理器,对数据进行计算,指挥电脑中的软件和硬件干活

cpu的分类:

​ AMD:

​ Inter:

线程是进程中的一个执行单元,负责程序的执行。

一个程序至少有一个进程,一个进程中包含多个线程

线程调度:

分时调度:

平均分配占用时间

抢占式调度:

优先级

4.3 创建线程类

单线程

主线程:执行主方法(main)的线程

单线程程序:java程序中只有一个线程

执行从main方法开始,从上到下依次执行

JVM执行main方法,main方法会进入到栈内存

JVM会找操作系统开辟一条main方法到cpu的执行路径

cpu就可以通过这个路径来执行main方法

而这个路径叫main(主)线程

public class Demo01MainThread {
    public static void main(String[] args) {
        Person p1 = new Person("小红");
        p1.run();
        Person p2 = new Person("小绿");
        p2.run();
    }
}
public class Person {
    private String name;

    public void run(){
        for (int i = 0; i < 20; i++) {
            System.out.println(name+"-->"+i);
        }
    }

    public Person() {
    }

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

    public String getName() {
        return name;
    }

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

多线程

创建多线程程序的第一种方式:创建Thread类的子类

实现步骤:

  1. 创建一个Thread类的子类

  2. 在Thread的子类中重写Thread类的run方法,设置线程任务

  3. 创建Thread的子类对象

  4. 调用Thread类中的方法start()方法,开启新的线程,执行run方法

    start()导致此线程开始执行;Java虚拟机调用此线程的run方法。

    结果是两个线程同时运行:当前线程(从调用返回到start方法)和另一个线程(执行其run方法)。

    不止一次启动线程是不合法的。 特别地,一旦线程完成执行就可能不会重新启动。

public class Demo01Thread {
   public static void main(String[] args) {
       MyThread myThread = new MyThread();
       myThread.start();
       for (int i = 0; i < 20; i++) {
           System.out.println("main:"+i);
       }
   }
}
public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("run:"+i);
        }
    }
}
posted @ 2021-11-08 15:30  盐汽水mua  阅读(45)  评论(0)    收藏  举报