Java进阶学习5:【异常、进程和线程、并发和并行、多线程】

  • A+
所属分类:Java Java进阶

01. 异常和错误的介绍

异常指的是不正常,指的是程序中出现了某些问题

    在Java中,所有的问题都可以使用一个类来表示,这个类叫做Throwable
    Throwable是所有异常和错误的父类。

    Throwable
        |-- Exception(异常):异常指的是程序中出现的一些轻微的问题,这些问题是可以挽回,补救的。 相                             当于人得了感冒。
        |-- Error(错误):错误指的是程序中出现的一些严重的,致命的问题, 这些问题不可挽回。 相当于人                         得了绝症。

02. 异常的继承体系以及异常的分类

参考 Java基础学习11:【异常、线程】中的图

03. 异常产生的过程

参考 Java基础学习11:【异常、线程】中的图

04. throw关键字手动抛出异常

/*
    如果不希望自动抛出异常,那么我们可以使用throw关键字手动抛出异常。
    throw的作用: 手动抛出一个异常对象。
    throw的格式:
        throw new 异常类名();
    在创建异常对象的时候,可以在构造方法中给出异常信息。
 */
public class Demo03Throw {
    public static void main(String[] args) {
        //定义数组
        int[] arr = new int[2];
        //调用getValue
        int value = getValue(arr, 10);
        System.out.println(value);
    }
    /*
        定义方法,获取数组中指定索引位置的元素
     */
    public static int getValue(int[] arr, int index) {
        //判断索引是否合法,如果索引不合法,那么就手动抛出一个异常。
        if(index < 0 || index >= arr.length) {
            //定义一个字符串,表示异常的提示信息
            String msg = "数组长度是" + arr.length + ", 最大的索引只能是" + (arr.length - 1) + ",您传递的索引是:" + index;
            //手动抛出一个异常
            throw new ArrayIndexOutOfBoundsException(msg);
        }

        int value = arr[index];
        return value;
    }
}

05. Objects的requireNonNull方法

/*
    Objects中有一个方法,可以判断一个对象是否为null,如果是null,那么就会抛出异常
        static T requireNonNull(T obj):判断参数obj是否为null,如果是null,那么抛出异常。
        static T requireNonNull(T obj, String message): 第二个参数表示异常信息。
 */
public class Demo04Objects {
    public static void main(String[] args) {
        //定义Object
        //Object obj = new Object();
        Object obj = null;

        //判断obj是否是null,如果是null,那么就手动抛出一个异常
        /*
        if(obj == null) {
            throw new NullPointerException();
        }
        */
        //使用Objects的requireNonNull 判断obj是否为null
        Objects.requireNonNull(obj, "obj是null, 不能通过null调用任何方法");

        //通过null调用任何方法都会引发空指针异常
        obj.toString();
    }
}

06. throws关键字的使用

/*
    throw: 用来手动抛出一个异常。
    throws: 表示进行异常声明, 声明这个方法是有可能抛出异常的。

    throws的使用格式:
        修饰符 返回值类型 方法名(参数列表) throws 异常类名{
            方法体;
        }

    throws的使用的注意事项:
        1. 如果一个方法内抛出了编译时异常, 那么则必须要使用throws进行异常声明
        2. 如果调用了一个使用throws声明了异常的方法,那么调用者如果进行try...catch(等会说), 那么也需要使用throws进行异常声明。
        3. 如果方法内抛出运行时异常,那么无需使用throws进行声明。
        4. 如果在一个方法内有可能抛出多个异常,那么我们需要进行多个异常的声明。
        5. 如果在一个方法内有可能抛出多个异常,那么我们也可以直接声明这些异常的父类异常。
 */
public class Demo05Throws {
    public static void main(String[] args) throws Exception{
        method();
    }

    //定义方法,抛出多个异常
    public static void method4() throws Exception{
        //定义变量
        int i = 10;
        //判断这个变量是奇数还是偶数,如果是奇数,抛出IOException,如果是偶数,那么就抛出SQLException
        if(i % 2 == 1) {
            throw new IOException();
        } else {
            throw new SQLException();
        }
    }

    //定义方法,抛出多个异常
    public static void method3() throws IOException, SQLException{
        //定义变量
        int i = 10;
        //判断这个变量是奇数还是偶数,如果是奇数,抛出IOException,如果是偶数,那么就抛出SQLException
        if(i % 2 == 1) {
            throw new IOException();
        } else {
            throw new SQLException();
        }
    }

    //抛出运行时异常
    public static void method2() {
        throw new RuntimeException();
    }

    //抛出编译时异常
    public static void method() throws Exception{
        throw new Exception();
    }
}

07. try...catch的使用

/*
    之前处理异常的方式都是甩锅, 把异常抛给调用者, 除了可以把异常抛给调用者之外,我们可以使用try...catch解决这个异常

    try...catch: 表示捕获处理, 表示真正解决掉了这个异常。

    try...catch格式:
        try {
            可能会出现问题的代码
        } catch(异常类名 变量名) {
            出现异常后执行的代码
        }

    try...catch的执行流程
        第一种情况: 如果try中的代码没有遇到问题, 那么代码会跳过catch继续往下执行。
        第二种情况: 如果try中的代码出现了异常, 并且catch捕获到了这个异常,代码会从try直接执行到catch。
        第三种情况: 如果try中的代码出现了异常,但是catch没有捕获到, 这个异常会依旧往外抛,抛给调用者。

    小结:
        异常处理有两种方式:
            1. 往外抛(甩锅): throw, throws
            2. 解决异常: try...catch
 */
public class Demo06TryCatch {
    public static void main(String[] args) {
        try {
            System.out.println("1. try...start");
            Object obj = null;
            obj.toString();//引发NullPointerException
            System.out.println("2. try...end");
        } catch(NullPointerException e) { //表示要捕获的异常是NullPointerException
            System.out.println("3. catch...");
        }
        System.out.println("4. main...end");
    }
}

08. finally代码块

/*
    try...catch后面可以在追加一个finally,finally中的代码,无论如何都会执行。

    格式:
        try {
            【A:可能会出现问题的代码】
        } catch (要捕获的异常类名 变量名) {
            【B:出现异常会执行的代码】
        } finally {
            【C: 一定会执行的代码】
        }

    执行流程:
        第一种情况: 如果try中的代码没有问题, 那么执行流程为【A】【C】
        第二种情况: 如果try中的代码有异常,并且catch捕获到了这个异常, 那么执行流程为:【A】【B】                   【C】
        第三种情况: 如果try中的代码有异常,但是catch没有捕获到这个异常,那么执行流程为:【A】【C】                    抛出异常

    finally中的代码一定会执行, 通常finally中的代码都用作资源回收(IO流中的关闭流, JDBC中的释放连接)
 */
public class Demo07TryCatchFinally {
    public static void main(String[] args) {
        try {
            System.out.println("1. try...start");
            //定义Object
            Object obj = null;
            obj.toString();
            System.out.println("2. try...end");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("3. catch...");
        } finally {
            System.out.println("4. finally...");
        }
        System.out.println("5. main...end");
    }
}

09. 编译时异常和运行时异常的区别

/*
    运行时异常和编译时异常的区别:
        1. 在方法内抛出运行时异常, 那么在编译时期可处理也可以不处理。
        2. 在方法内抛出编译时异常, 那么在编译时期必须要处理, 要么使用throws声明这个异常是往外抛的,要么使用try...catch解决这个异常。
 */
public class Demo08RuntimeException {
    public static void main(String[] args) {
        //method();
        //method2();
    }

    /*
        方法中抛出运行时异常(在编译时期可以处理,也可以不处理)
     */
    public static void method2() {
        throw new RuntimeException();
    }

    /*
        方法中抛出编译时异常(必须处理,要么try...catch,要么throws)
     */
    public static void method() throws Exception{
        throw new Exception();
    }
}

10. 继承中方法重写的异常注意事项

/*
    继承关系中方法重写时异常的注意事项:
        1. 如果父类方法没有抛出异常,那么子类重写该方法时也不能抛出异常, 如果该方法中有异常,只能try...catch
        2. 如果父类方法抛出了异常, 那么子类重写该方法时,可以抛,也可以不抛.
           如果抛, 那么要么抛出和父类方法相同的异常,要么抛出父类方法的子类异常。

    上面的注意事项只适用于编译时异常。
 */
public class Zi extends Fu{

    @Override
    public void function() throws FileNotFoundException{
        System.out.println("子类重写的function方法");
    }

    @Override
    public void method() {
        System.out.println("子类重写的method方法");
        //定义字符串
        String str = "2018-03-28 16:20:37";
        //创建SimpleDateFormat对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //调用parse方法,将字符串转成Date
        try {
            Date date = sdf.parse(str);
        } catch (ParseException e) {

        }
    }
}

public class Fu {
    public void function() throws IOException{
        System.out.println("父类的function方法");
    }

    public void method() {
        System.out.println("父类method方法");
    }
}

11. 多catch处理的注意事项

/*
    如果要使用try...catch语句捕获多个异常,那么可以在这个语句后面跟上多个catch

    格式:
        try {
            可能会出现问题的代码
        } catch(要捕获的异常类 变量名) {
            出现该异常后的处理方式
        } catch(要捕获的异常类 变量名) {
            出现该异常后的处理方式
        } catch(要捕获的异常类 变量名) {
            出现该异常后的处理方式
        }

    执行流程:
        1. 会先执行try中的代码。
        2. 如果try中的代码没有异常,那么所有的catch都不会执行。
           如果try中的代码有异常,那么哪个catch先捕获到这个异常,那么就执行哪个catch中的语句。 剩下的catch就不再执行了

    注意事项:
        如果使用catch捕获多个异常,那么父类异常不能放在子类异常的前面。
 */
public class Demo09CatchCatch {
    public static void main(String[] args) {
        try {
            Object obj = null;
            obj.toString(); //空指针异常
            System.out.println("1. try...end");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("2. ArrayIndexOutOfBoundsException...");
        } catch (NullPointerException e) {
            System.out.println("3. NullPointerException...");
        } catch (ClassCastException e) {
            System.out.println("4. ClassCastException...");
        } catch (Exception e) {
            System.out.println("5. Exception");
        }

    }
}

12. Throwable的常见方法

/*
    在Throwable中有一些方法可以获取到异常信息。
        void printStackTrace(): 将详细的异常信息进行输出。
        String getMessage(): 获取简单异常信息,并将该异常信息返回。

    上面的方法不能直接创建对象,然后去调用,上面的方法要放在catch中去使用。
 */
public class Demo10ThrowableMethod {
    public static void main(String[] args) {
        try {
            //定义数组
            int[] arr = new int[2];
            System.out.println(arr[10]); //抛出一个ArrayIndexOutOfBoundsException异常对象
            System.out.println("1.try...end");
        } catch (ArrayIndexOutOfBoundsException e) {//e表示的是捕获到的异常对象。
            //通过e调用printStackTrace输出异常信息
            e.printStackTrace();

            //String getMessage(): 获取简单异常信息,并将该异常信息返回。
            //System.out.println(e.getMessage());
        }
        System.out.println("2.main...end");
    }
}

13. 自定义异常

/*
    要求:模拟注册操作, 如果用户名已经存在,那么就抛出异常并提示,用户名已经注册
 */
public class Demo01Test {
    //定义数组,当做数据库, 用来存储所有的用户名
    static String[] arr = {"jack", "rose", "tom"};

    public static void main(String[] args) {
        try {
            checkUsername("tom");
            System.out.println("该用户名不存在,那么可以注册");
        } catch (RegistException e) {
            System.out.println(e.getMessage());
        } catch (Exception e) { //捕获其他异常
            System.out.println("对不起,服务器忙");
        }
    }

    /*
        定义方法,检测用户名是否已经存在,如果已经存在,那么就抛出异常。
                 如果要注册的用户名不存在,那么这个方法就不会抛出异常。
     */
    public static void checkUsername(String username) {
        //System.out.println(10 / 0); //除0异常
        //遍历arr数组,拿到里面的每一个元素, 判断username和遍历到的元素是否相同,如果相同,表示要注册的用户名已经存在,那么就抛出异常
        for(String thisUserName : arr) {
            if(thisUserName.equals(username)) {
                //如果相同,表示用户名已经存在,那么就抛出异常
                throw new RegistException("用户名已经存在,不能注册");

            }
        }
    }
}

/*
    如何自定义异常?
        认贼作父, 找一个异常类当做父类。

    如果类继承的是编译时异常类,那么这个类就是编译时异常。
    如果类继承的是运行时异常类,那么这个类就是运行时异常。
 */
public class RegistException extends RuntimeException{ //该类继承了RuntimeException,那么这个类就是一个运行时异常。
    //提供一个构造方法,用来接收异常信息,并且设置异常信息
    public RegistException(String msg) {//msg表示的就是异常信息
        super(msg);//将异常信息交给父类,由父类完成赋值
    }

    //提供空参构造
    public RegistException() {

    }
}

14. 进程的概念

参考 Java基础学习11:【异常、线程】中的图

15. 线程的介绍

参考 Java基础学习11:【异常、线程】中的图

16. 并发和并行的介绍

参考 Java基础学习11:【异常、线程】中的图

17. 程序中的main线程

/*
    每一个程序都至少要包含一个线程, 我们之前写的Java程序也一样。
    当我们运行程序的时候,JVM会创建一个main线程, main线程去执行main方法

    如果一个程序只有一个线程,那么这个程序就是一个单线程程序,单线程程序同时只能执行
    一个任务,如果有多个任务, 那么只能先执行完其中一个,再执行另一个。

    如果想要同时执行多个任务,可以使用多线程程序。
 */
public class Demo01MainThread {
    public static void main(String[] args) {
        System.out.println("main...start");
        //输出100行HelloWorld
        for(int i = 0; i < 100; i++) {
            System.out.println("HelloWorld:" + i);
        }
        //输出100行HelloJava
        for(int i = 0; i < 100; i++) {
            System.out.println("HelloJava:" + i);
        }

    }
}

18. 多线程程序的实现

/*
    在Java中,有一个类,叫做Thread,这个类表示线程类,并且我们可以使用这个类去实现多线程程序。

    多线程的创建步骤:
        1. 定义一个类,去继承Thread类。
        2. 在这个类中重写Thread类的run方法, 并在run方法中编写线程要执行的任务。
        3. 创建Thread子类对象
        4. 调用Thread子类对象的start方法启动线程, 线程会执行自己的run方法。

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

 */
public class Demo02Thead {
    public static void main(String[] args) {
        //创建Thread子类对象
        //表示创建一个线程对象,只不过这个线程还没有执行。
        MyThread m = new MyThread();
        //调用Thread子类对象的start方法启动线程, 线程会执行自己的run方法。
        m.start();
        //输出100次HelloWorld
        for(int i = 0; i < 100; i++) {
            System.out.println("main线程正在输出HelloWorld:" + i);
        }
    }
}

/*
    Thread是线程类,当MyThread继承线程类,MyThread也就变成了线程类
 */
public class MyThread extends Thread{
    //重写run方法,在run方法中定义线程要执行的任务
    @Override
    public void run() {
        //输出100次HelloJava
        for(int i = 0; i < 100; i++) {
            System.out.println("新线程在输出HelloJava:" + i);
        }
    }
}
  • 资源分享QQ群
  • weinxin
  • 官方微信公众号
  • weinxin
沙海
一个Java基础入门的教程视频
TripodCloud:性价比最高的CN2 GIA服务器
动力节点最牛Java自学基础教程
专业承接各类企业网站的开发和维护

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: