异常,多线程的创建

异常

异常的概念以及分类

  • 指的是程序在执行的过程中,出现的非正常的情况,最终会导致JVM的非正常停止

  • 异常的根类是java.lang.Throwable,它下面有两个子类.java.lang.Exception以及java.lang.Error,其中Exception下有一个子类是RuntimeException

  • Error:工程师不能处理,只能尽量避免,是不可预知的.Error代表错误.相当于程序得了一个无法治愈的毛病,必须修改源代码,程序才能继续运行

  • Exception:由于使用不当导致,可以避免,是编译时期的异常,进行编译(写代码)java程序出现的问题,RuntimeException:运行时期异常,java程序运行过程中出现的问题,相当于程序出现了一个小毛病,把异常处理掉,程序才能继续执行

异常的处理

  • throw关键字(如果不抛出异常,jvm也会自动帮我们抛出异常,使我们的异常更容易被理解)

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

    • 使用格式:throw new XXXException("异常产生的原因")

    • 注意:

      • throw关键字必须写在方法的内部

      • throw关键字后边new的对象此项是Exception或者其子类对象

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

      • throw关键字后边创建的是RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给JVM处理(打印异常对象,中断程序)

        如果是编译时期异常,我们就必须处理这个异常,要么trycatch,要么throws.

  • 程序的健壮性判断: 可以借助Object的工具类:Objects

    • public static <T> T requireNonNull(T obj) {
      ​
      if (obj == null)
      ​
      throw new NullPointerException();
      ​
      return obj;
      ​
      }
    • 这个还有一个重载,参数为(T obj , String message)

异常处理的两种方式

throws关键字

  • throws关键字:异常处理的第一种方式,交给别人处理

  • throws 基本都是编译时期的异常时(又不想使用try)

  • 作用:

    • 当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象

    • 可以适应throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理(自己不处理,给别人处理),最终交给jvm处理-->中断处理

  • 使用格式:在方法声明的同时使用

  • 注意:

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

    • throws关键字后边声明的异常必须是Exception或者是其子类

    • 方法内部如果抛出了多个异常对象,那么throws后边也必须声明多个异常对象,如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可

    • 调用了一个声明抛出异常的方法,我们就必须处理声明的异常,要么继续使用throws声明抛出,交给方法的调用者处理,最终交给jvm,要么try...catch自己处理异常

  • 最简单的使用: throws Exception(因为异常继承自Exception)

try...catch

  • 异常处理的第二种方式,自己处理异常

  • 格式:

    try{

可能产生异常的代码

}catch(){

异常的处理逻辑,怎么处理异常对象

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

}

  • 注意:

    • try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象

    • 如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try...catch之后的代码

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

    • try...catch是捕获不了错误的.

Throwable类的几个方法

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

  • String toString():返回此throwable的详细描述字符串

  • void printStackTrace:jvm打印异常,默认此方法,打印的是最全面的

finally代码块

  • finally代码块是与try一起使用的

    try{

    可能产生异常的代码

    }catch(){

    异常的处理逻辑,怎么处理异常对象

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

    }finally{

    无论是否出现异常都会执行

    }

  • 注意:

    • finally不能单独使用,必须和try一起使用

    • finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要释放(IO流)

异常注意事项

  • 多个异常的捕获处理

    1. 多个异常分别处理

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

      一个try多个catch的注意事项

      • catch里面的异常变量,如果有子父类关系,那么子类的异常变量必须下载上边,否则会报错

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

  • 注意:运行时候的异常.可以不处理,即不捕获也不声明抛出,默认给jvm处理

  • 如果finally里面有return语句,则永远返回finally中的结果,避免该情况

  • 子父类的异常

    • 如果父类抛出了多个异常,子类重写父类方法的时候,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常

    • 父类方法中没有抛出异常,子类重写该方法时候也不可以抛出异常.此时子类产生的异常,只能捕获处理,不能声明抛出.

    • 注意:父类异常时什么样子,子类异常就什么样子

自定义异常

  • java给我们提供的异常类不够的时候,我们自定义一个异常类.

  • 格式:

    public class XXXException extends Exception|RuntimeException{

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

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

    }

  • 注意:

    • 自定义异常类一般都是以Exception结尾,说明该类是一个异常类

    • 自定义异常类,必须继承Exception或者RuntimeException

      如果继承Exception,那么自定义的异常类就是一个编译时期异常,如果方法内部抛出了编译时期异常,就必须处理这个异常,要么throws要么try...catch

      如果继承RuntimeException,就是运行时期的异常,我们无需处理,交给jvm处理(终端处理)

自定义异常类练习

在一款角色扮演游戏中,每一个人都会有名字和生命值;角色的生命值不能为负数

要求:当一个人物的生命值为负数negative的时候需要抛出自定的异常

person类
package com.qin.test.Test10;
​
public class Person {
    private String name;
    private int lifeValue;
​
    public Person() {
    }
​
    public Person(String name, int lifeValue) throws LifeValueNegativeException {
        this.name = name;
        if (lifeValue < 0) {
            throw new LifeValueNegativeException("生命值为负异常.");
        } else {
            this.lifeValue = lifeValue;
        }
​
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getLifeValue() {
        return lifeValue;
    }
​
    public void setLifeValue(int lifeValue) throws LifeValueNegativeException {
        if (lifeValue < 0) {
            throw new LifeValueNegativeException("生命值为负异常.");
        } else {
            this.lifeValue = lifeValue;
​
        }
    }
}
​
自定义异常类
package com.qin.test.Test10;
​
public class LifeValueNegativeException extends Exception {
    public LifeValueNegativeException() {
    }
​
    public LifeValueNegativeException(String message) {
        super(message);
    }
}
​
Test类
package com.qin.test.Test10;
​
public class PersonTest {
    public static void main(String[] args) {
        try {
            Person person = new Person("jack",-1000);
        } catch (LifeValueNegativeException e) {
            e.printStackTrace();
        }
​
    }
}
//com.qin.test.Test10.LifeValueNegativeException: 生命值为负异常.
//at com.qin.test.Test10.Person.<init>(Person.java:13)
//at com.qin.test.Test10.PersonTest.main(PersonTest.java:6)
​

多线程

  • 并发:指两个或多个事件在同一个时间段内发生

    • 相当于一个人吃两个馒头

  • 并行:指两个或多个事件在同一时刻发生(同时发生)

    • 相当于两个人吃两个馒头

  • 进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。

  • 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

  • java采用的是抢占式调度

  • 主线程:(执行main方法的线程.)程序入口所在的线程就是主线程.

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

  • 使用线程名.run()也会调用,但是没有调用线程

多线程练习题

创建三个子线程,在每个线程中开启10万次的循环,线程1循环中将循环自增变量i赋值给Integer类型变量 a,线程2循环中将字符串"黑马程序员"赋值给String类型变量b,线程3循环中将字符串"黑马程序员"和循环自增变量i拼接后赋值给String类型变量c

分别计算三个线程完成任务所用的毫秒值

main方法
public class Test11 {
    public static void main(String[] args) {
        MyThread1 m1 = new MyThread1();
        MyThread2 m2 = new MyThread2();
        MyThread3 m3 = new MyThread3();
​
        m1.start();
        m2.start();
        m3.start();
​
    }
}
1,2,3子线程类
​
package com.qin.test.Test11;
​
public class MyThread1 extends Thread {
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        Integer a = 0;
        for (int i = 0; i < 100000; i++) {
            a = i;
        }
        long end = System.currentTimeMillis();
        long time = end - start;
        System.out.println("线程1:"+time);
    }
}
​
package com.qin.test.Test11;
​
public class MyThread2 extends Thread {
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        String b = "";
        for (int i = 0; i < 100000; i++) {
            b = "黑马程序员";
        }
        long end = System.currentTimeMillis();
        long time = end - start;
        System.out.println("线程2:"+time);
    }
}
​
package com.qin.test.Test11;
​
public class MyThread3 extends Thread {
    @Override
    public void run() {
        long start = System.currentTimeMillis();
        String c = "";
        for (int i = 0; i < 100000; i++) {
            c = "黑马程序员"+i;
        }
        long end = System.currentTimeMillis();
        long time = end - start;
        System.out.println("线程3:"+time);
    }
}
// 结果
//
//线程1:4
//线程2:1
//线程3:54

猜你喜欢

转载自blog.csdn.net/qq_35472880/article/details/81487259