黑马程序员技术交流社区

标题: [石家庄校区]就业班JavaSE高级部分day05 异常 线程 [打印本页]

作者: 湿漉漉的文字控    时间: 2018-11-20 15:51
标题: [石家庄校区]就业班JavaSE高级部分day05 异常 线程
就业班JavaSE高级部分day05 异常 线程
异常:
异常的概念:
至在程序的执行过程中,出现的非正常现象,导致JVM非正常停止.
异常的分类:
Exception:编译期异常,进行编译java程序时出现的问题
RuntimeException:运行期异常,java程序运行过程中出现的问题
Error:错误, 必须修改源代码,程序才能执行
例:
编译异常和解决方法
C:/Users/Administrator/AppData/Local/YNote/data/weixinobU7VjkOlFOSrTPAb-ROkG2i_vds/959fb00d3875457fbe1882e67cba2e2f/c3a4c514d769499c8268573f58c47df5.jpg
运行期异常 使用try catch方法使接下来的程序还能继续执行
只有在运行时才能发现问题
C:/Users/Administrator/AppData/Local/YNote/data/weixinobU7VjkOlFOSrTPAb-ROkG2i_vds/645c8a6830694ff4ae7a22107bb0e41b/047be550dd514a2185dfe1d2803b4f7f.jpg
错误:必须修改源代码,否则不能解决问题
C:/Users/Administrator/AppData/Local/YNote/data/weixinobU7VjkOlFOSrTPAb-ROkG2i_vds/9238bae3519f4ff48e8ed5f0a3a2ed58/616eccbcbed34e8398ce27b01de1b209.jpg
异常的处理:
throw关键字:
在指定的方法中抛出指定的异常
格式:
throw new xxxExcetpion(异常出现的原因)
注意:
1.写在方法内部
2. 关键字后边new的对象必须是Excetpion或者Exception的子类
3.throw关键字抛出指定异常对象,我们必须对这个异常进行处理
throw后创建的是RuntimeException或者是RuntimeException的子类对象,我们可以          不处理默认交给JVM处理(打印异常对象,中断程序)
throw关键字后边创建的是编译期异常,我们必须吃力这个异常,要么throws,要么try...catch
C:/Users/Administrator/AppData/Local/YNote/data/weixinobU7VjkOlFOSrTPAb-ROkG2i_vds/c0dfd3285e444962b7aa3da8f952cae6/2cc98a0b4de64948aae77702c0fdb736.jpg
throws关键字:异常处理的第一种方式.交给别人处理
作用:
当方法内部抛出异常对象的时候,我们不需处理这个异常
注意:
1. throws 必须写在方法声明上
2. throws 后面的异常类名, 一般是 Exception 或 Exception的子类
        (RuntimeException及其子类也行, 但是没有什么意义)
3. 方法内部如果抛出了多个异常对象, throws 后也必须声明多个异常
        如果抛出的异常对象有子父类关系, 那么直接声明父类异常即可
4. 调用了一个带有 throws 声明抛出异常的方法, 就必须处理该异常:
        要么继续声明 throws 抛出
        要么 try...catch 捕获处理异常
捕获异常:
try...catch:
        捕获并处理异常 (方法内部自己处理异常, 不交给别人, "自己背锅")
格式:
    try {
        // 可能产生异常的代码
    } catch (异常类名 变量名) {
        // 处理异常的代码
        // 一般会将异常信息存储到日志中
    }
        ...
        } catch (异常类名 变量名) {
        // 处理异常的代码
        // 一般会将异常信息存储到日志中
    }
注意:
        1. try 中可能会抛出多种异常, 就可以写多个 catch 分别处理每种异常
        2. 如果 try 中产生了异常, 就会从产生异常的那一行代码直接跳转到对应的 catch         中执行处理代码, 然后继续执行 try...catch 之后的其他代码;
如果 try 中没有产生异常, 那就不会执行 catch , 执行完 try 中的代码后, 继续执行 try...catch 之后的其他代码
Throwable中的3个异常处理方法
java.lang.Throwable
        // 成员方法
        String getMessage(): 异常的信息. 没有原因返回null
        String toString(): 异常的类型和原因信息
        void printStackTrace(): 使用标准错误输出流打印异常信息
finally代码块
格式:
    try {
        // 可能发生异常的代码
    } catch(异常类型 异常变量名) {
        // 处理异常
    }
        ...
        catch(异常类型 异常变量名) {
        // 处理异常
    } finally {
        // 无论是否发生异常, 是否捕获, 最后都会执行的代码.
        // 通常在这里执行释放资源的操作
    }
注意:
        1. finally 必须和 try...catch 一起使用
        2. finally 一般用于释放资源 (IO流时用到)
捕获多个异常:
        1. 多个异常分别 try...catch 处理
        2. 一个 try 多个 catch
        如果异常存在继承关系, 子类异常在上, 父类异常在下
        3. 多个异常, 一次捕获一次处理
                用Exception多态捕获
        // 1. 多个异常分别try...catch处理
    try {
            // 可能发生异常的代码
    } catch (异常类型 变量名) {
            // 处理异常
    }   
    try {
            // 可能发生异常的代码
    } catch (异常类型 变量名) {
            // 处理异常
    }   
        // 2. 一个try多个catch
        try {
        // 可能发生异常的代码
        // 可能发生异常的代码
        // 可能发生异常的代码
    }catch (异常类型1 变量名){  // 子类异常在上
        // 处理异常1
    }catch (异常类型2 变量名){  // 父类异常在下
        // 处理异常2
    }
        // 3.
        try {
                // 可能发生异常的代码
        // 可能发生异常的代码
        // 可能发生异常的代码
        // 可能发生异常的代码
        // 可能发生异常的代码
    }catch (Exception e){  // 父类异常多态接收
        // 处理异常
    }
运行时异常, 可以不抛出 throws 也不捕获 try catch, 交给JVM处理
        // 因为可以通过某些代码来避免发生运行时异常
        // 通过if判断, 避免可能发生的ArrayIndexOutOfBoundsException
    if (i >= 0 || i <= arr.length-1) {
        int a = arr;
    }
        // 通过if判断, 避免可能发生的NullPointerException
    if (phone != null) {
        phone.call();
    }
注意:
如果 finally 代码块中有 return 语句, 则永远返回 finally 中的 return 语句的值
应该避免在 finally 中写 return 语句
子父类继承关系下, 子类重写父类带有 throws 的方法:
        1. 如果父类抛出多个异常, 子类重写父类方法时可以有3种方式:
                a: 抛出和父类相同的异常
                b: 抛出父类异常的子类
                c: 不抛出异常
        2. 父类方法没有抛出异常, 子类重写父类该方法时也不可抛出异常
                此时子类产生该异常, 只能捕获处理, 不能声明抛出
一般情况下:
    父类方法声明的异常是什么样的, 子类重写的方法声明异常就什么样, 保持一致即可
自定义异常类的使用案例:
public class RegisterException extends Exception {
//public class RegisterException extends RuntimeException {

    // 异常类的构造方法也可以用快捷键生成:
    // Alt + Insert, 选Constructor,
    // 只选 空参 和 有String参数的 即可
    public RegisterException() {
    }
    public RegisterException(String message) {
        super(message);
    }
}​
public class Test {
​    // 定义静态成员变量保存已经注册的用户名
    private static String[] usernames = {"张三", "李四", "王五"};
    public static void main(String[] args) {
        // 键盘录入要注册的用户名
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要注册的用户名:");
        String username = scanner.next();
        // 调用检测用户名的方法
        try {
            checkUsername(username);  // 编译时异常在写代码时必须写好处理方案
        } catch (RegisterException e) {
//            e.printStackTrace();
            // 可以自己来实现处理方式. 模拟将异常的原因用弹窗显示出来
            System.out.println("[弹窗提示]: " + e.getMessage());
        }
    }
    // 定义方法来判断指定的用户名是否已被注册
    public static void checkUsername(String username) throws RegisterException {
        // 遍历数组
        for (String name : usernames) {
            // 如果有任意一个名字和输入的用户名相同, 则说明已被占用
            if (name.equals(username)) {
                // 通过抛出异常的方式 来通知方法调用处
                throw new RegisterException("亲,该用户名已经被注册");
                // throw 异常 本身也能结束方法的执行
            }
        }
        // 如果程序能执行到这里, 说明没有抛出异常, 即没有重名, 可以注册
        System.out.println("恭喜您, 注册成功!");
    }
}
并发与并行
并发: (交替执行) 指两个或多个事件在"同一时间段内"发生
并行: (同时执行) 指两个或多个事件在"同一时刻"发生 (同时发生)   
我们研究的是"并发"
并发的实现, 是依靠电脑CPU快速地在多个任务之间切换执行实现的
进程:
进程: 一个应用程序在内存中的一次执行过程
        每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程
        进程也是程序的一次执行过程,是系统运行程序的基本单位
        系统运行一个程序即是一个进程从创建、运行到消亡的过程
线程:
线程: 是进程内的一个独立执行单元 (一条代码执行路径)
        一个程序运行后至少有一个进程, 一个进程中可以包含多个线程
        公司 > 部门 > 员工
        程序 > 进程 > 线程
多线程的好处:
        效率高
        多个线程之间互不影响       
        1CPU    10线程 + 1我的线程  1/11   10线程 + 10我的线程   10/20  1/2
线程的调度:
线程的调度方式:
        1. 分时调度: 所有线程轮流使用CPU, 平分占用CPU的时间
        2. 抢占式调度: 优先让优先级高的线程使用CPU; 如果优先级相同, 则随机选择一个线程执行
        1-10
        线程1 5 可能性更大
        线程2 5
        线程3
Java使用的是"抢占式"调度
主线程:
Exception in thread "main"
主线程:
        我们以前编写的代码, 也在一条线程中执行, 该线程叫作"main线程", 也称为"主线程"
如果我们没有额外创建线程, 那么我们的程序就只有一个线程, 即主线程, 此时程序是"单线程"的
单线程的执行特点:
        同一个线程内的代码, 从上往下依次执行
创建多线程程序的第一种方式: 继承Thread类
实现多线程的第一种方式:
        1. 定义类, 继承 Thread 类
        2. 重写 run() 方法, run方法内部是线程要执行的任务
        3. 创建Thread子类的对象, 调用 start() 方法启动线程
java.lang.Thread类: 表示线程. 实现了Runnable接口
    void start(): 启动线程, 即让线程开始执行run()方法中的代码
注意:
        必须调用 start() 方法来开启线程, 不能直接调用 run() 方法, 调用 run() 会变成单线程
        同一个线程对象, 不能多次调用 start() 方法
        Java是抢占式调度, 不同线程的代码, 执行顺序是随机的






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2