- 异常
- 线程
分辨程序中异常和错误的区别
说出异常的分类
掌握虚拟机处理异常的方式
列举出四个常见的运行期异常
使用try-catch关键字处理异常
使用throws关键字处理异常
自定义异常类并处理之
说出进程、线程的概念
理解并发与并行的区别
开启新线程
异常
概念:异常即不正常。和正常情况有所区别,该异常部位功能受到影响。
程序异常指在程序运行过程中,出现非正常情况,最终会导致JVM的非正常停止。在Java等面向对象的编程语言中,异常本身就是一个类,产生异常就是创建异常对象并抛出了一个异常对象,Java处理异常的方式是:中断处理。
备注:异常指的并不是语法错误,语法错误并不能通过编译,不会产生字节码文件,根本不能进入运行
异常体系
异常机制可以帮助我们找到程序中出现的问题,异常的根类是java.lang.Throwable
,它的下面有两个子类:java.lang.Error
和java.lang.Exception
,平常说的异常指的是 java.lang.Exception
Throwable体系:
- Error:严重错误,无法通过异常处理解决,好比绝症,只能事先预防
- Exception:异常,异常产生后程序员可以通过适当的代码进行纠正处理,使程序能够继续进行下去,好比感冒吃药。
* java.lang.Throwable
* |-----java.lang.Error:一般不编写针对性的代码进行处理。
* |-----(虚拟机错误)VirtulMachineError
* |-----StackOverFlowError
* |-----(内存溢出异常)OutOfMemorError
* |-----AWTError
* |-----LinkageError
* |-----java.lang.Exception:可以进行异常的处理
* |------编译时异常(checked)
* |-----IOException
* |-----FileNotFoundException
* |-----ClassNotFoundException
* |------运行时异常(unchecked,RuntimeException)
* |-----NullPointerException
* |-----ArrayIndexOutOfBoundsException
* |-----ClassCastException
* |-----NumberFormatException
* |-----InputMismatchException
* |-----ArithmeticException
* |-----NoSuchElementExceprion
* |-----SQLException
异常的处理
Java异常处理的五个关键字:try catch finally throw throws
抛出异常throw
当我们在编写程序的时候,我们必须考虑程序可能出现的问题,比如说:在定义方法的时候,方法需要接收参数、对于调用者来说,当调用方法的时候需要接收参数,首先需要对参数数据进行合法的判断,若数据不合法,就应该告诉调用者,传递合法的数据进来。这时候就需要使用抛出异常的方式来告诉调用者。
在Java当中,提供了一个关键字throw,用来抛出一个指定的异常对象。操作步骤:
- 创建一个异常对象,封装提示信息
- 需要将这个异常对象告知给调用者,通过关键字throw就可以完成。throw抛出一个异常对象
备注:throw一般用在方法内,用来抛出一个具体的异常对象,将这个异常对象抛出给调用者处并结束当前方法的执行
使用格式:
throw new 异常类名 (参数)
示例:
//给调用者抛出一个空指针异常
throw new NullPointException("要访问的数组索引不存在");
//索引越界
throw new IndexOutOfBoundException("该索引超出引用范围");
Objects非空判断
在该类中,提供了一些静态的实用方法,这些方法是null-safe(空指针安全)或者null-tolerant(容忍空指针的),在源码当中,对对象的null值进行了抛出异常的操作。
public static
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
声明异常处理throws
声明异常:将问题标识出来、报告给调用者,如果方法内通过throw抛出了一个编译期异常,又没有通过捕获处理异常,那么必须通过throws进行声明,让调用者处理。
关键字throws运用在方法的声明上,用于表示当前方法不处理异常,提醒调用者处理该异常(该方法携带异常)。
声明异常处理的格式:
修饰符 返回值类型 方法名(参数列表) throws XxxException1,XxxException2,...{//或多个异常种类
}
示例:
public class ThrowsDemo{
public static void main(String []args){
read("C:/a.txt");
}
public static void read(String path) throws FileNotFoundException{
//校验 如果传递的路径不是以.txt结尾的,抛给调用者文件找不到异常
if(!path.endsWith(".txt")){
//抛出文件找不到异常
throw new FileNotFoundException("文件找不到");
}
}
}
捕获异常try-catch
如果异常出现的话,会立刻终止程序
处理方式:
1.如果使用throws关键字来声明式处理,相当于没有处理。异常交给方法的调用者
2.在方法中使用try-catch语句块处理异常
try-catch的方式就是捕获异常
- 捕获异常:Java中对异常有针对性的语句块来进行捕获,可以对出现的异常进行指定的方式处理
格式:
try{
//可能会出现异常的代码
} catch (异常类型 e){
//处理异常的逻辑代码
//记录日志 //打印异常信息 //继续向上抛(不建议)
}
try:该语句块中可能出现异常的代码
catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理
备注:try 和 catch都不能单独使用,一般建议连用
public class TryCatchDemo{
public static void main(String []args){
try{
readFile("D:\a.txt");
}catch(FileNotFoundException e){//try中抛出的是什么异常类型,在括号中就定义什么异常类型
//打印异常信息
System.out.print(e);
}
}
public static void readFile(String path) throws FileNotFoundException{
if(!path.startsWith("C:")){
throw new FileNotFoundException("文件找不到");
}
}
}
如何获取异常的信息
Throwable类中定义了一些常用的API方法
-
public String getMessage():获取异常的描述信息和原因(提示给用户错误原因)
-
public String toString():获取异常的类型、异常的描述信息
-
public void printStackTrace():打印异常的跟踪栈信息并且输出到控制台中
包含了异常的类型、异常的原因、还包括异常出现的位置,在开发和调试阶段,一般都使用printStackTrace方法
finally语句块
finally:有一些特定的代码,无论异常是否发生,都需要执行,当程序发生异常时,会引发程序的跳跃性,导致有一些代码加载不到,而finally语句块就是用来解决这样的问题的,在finally语句块中存放的代码一般都是一定会被执行到的
什么样的代码最终一定要被执行?
比如:在try中打开了一些物理资源(磁盘文件、网络连接、数据库的连接),我们一般在使用完毕后必须关闭掉,可以使用finally语句块来实现。
finally语句块的语法格式:
try{
// ...
}catch(异常类型 e){
// ...
}...
finally{
// ...
}
备注:中间的catch语句块可以省略,finally不能单独使用。建议连用
public class FinallyDemo01{
public static void main(String []args){
try{
readFile("D:\a.txt");
}catch(FileNotFoundException e){//try中抛出的是什么异常类型,在括号中就定义什么异常类型
//打印异常信息
System.out.print(e);
}
finally{
System.out.println("不管程序如何运行,此行代码一定被加载");
System.out.println("此处可以进行资源关闭");
}
}
public static void readFile(String path) throws FileNotFoundException{
if(!path.startsWith("C:")){
throw new FileNotFoundException("文件找不到");
}
}
}
备注:
1.如果finally语句块中有return语句,永远返回的是finally语句块中的结果值
2.当只有在try或者catch中调用退出JVM的相关方法,此时finally才不会被执行到,否则finally永远被执行
异常的注意事项
当程序中出现了多个异常,那么又该如何捕获和处理呢?
- 多个异常,分别处理
- 多个异常一次捕获、多次处理
- 多个异常一次捕获、一次处理
一般我们都是使用一次捕获、多次处理的方式
try {
//可能出现异常的代码 多个异常
} catch (异常类型A e){ //当try中出现A异常的时候,用改catch来捕获
//处理异常的逻辑
}catch (异常类型B e){ //当try中出现B异常的时候,用改catch来捕获
//处理异常的逻辑
}catch (异常类型C e){ //当try中出现C异常的时候,用改catch来捕获
//处理异常的逻辑
}
...
注意:这种异常处理方式,要求多个catch的异常不能相同,并且若catch中的多个异常之间存在子父类关系,那么子类异常的处理要求在父类异常处理的上面,父类异常的处理在下面
子父重写时异常:
- 运行时异常被抛出可以不处理,即不捕获也不声明
- 如果finally中有return语句,那么永远返回finally语句块中的结果值
- 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者父类异常的子类或者不抛出异常
- 父类方法如果没有抛出异常,子类重写该方法时也不可能抛出异常。此时子类方法内产生了异常,只能捕获处理,不可声明抛出
自定义异常
Java中根据不同的情况提供了不同的异常类,JDK官方提供的异常类始终是有限的,大多数情况下我们需要根据自己的业务需要来定义异常类,例如:年龄负数异常、成绩负数异常、登陆异常等等
什么是自定义异常类?
在开发中,根据自己业务的异常情况来定义异常类。
例如:自定义一个业务逻辑异常类: 注册异常 RegisterException
异常类定义的两种方式:
- 自定义一个编译期异常类,自定义类继承于
java.lang.Exception
- 自定义运行期异常类,继承于
java.lang.RuntimeException
//首先定义一个注册异常类 RegisterException
public class RegisterException extends RuntimeException{
//空参构造
public RegisterException (){
}
//有参构造
public RegisterException (String message){
super(message);
}
}
public class Demo{
//使用数组模拟数据库 已存在多个账户名称
public static String[] names = {"校长","小王"};
public static void main(String []args){
String name = new Scanner(System.in).next();
//校验账户是否出现异常
try{
checkName(name);
System.out.println("注册成功!!!");
names = Arrays.copyOf(name,names.length+1);
names[names.length-1] = name;
}catch(){
e.printStackExceptionn;
}
}
public static boolean checkName(String userName) throws RigisterException{
for(String name : names){
if(name.equals(userName)){
throw new RigisterException("你的名字已经被注册过了");
}
}
}
}