1.1 异常概念
1.1.1异常的继承体系
- 学习异常处理的目的
- 不能让程序因为一个小小的问题而导致整个程序崩溃。
- 什么是异常
- 在程序编译或运行过程中出现的问题则称为异常,最终会导致JVM非正常停止。
- 异常的继承体系
- Throwable类是Java语言中所有错误或异常的超类
- Error:错误
- Exception:异常(编译时异常、运行时异常)
在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处 理异常的方式是中断处理。
1.1.2 Throwable常用方法
- public String getMessage():获得异常信息字符串。
- public String toString():获得异常详细信息字符串:类全名:异常原因。
- public printStackTrace();追踪异常的栈信息。(追踪异常的根源)
即打印异常的详细信息。包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。
注意:在实际开发过程中,出现异常可以把异常的简单类名,拷贝到API中去查。
/*
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at day05Test01.PrintStackTraceDemo01.main(PrintStackTraceDemo01.java:6)
异常出现的位置:at day05Test01.PrintStackTraceDemo01.main(PrintStackTraceDemo01.java:6)
异常的类型:java.lang.ArrayIndexOutOfBoundsException
异常的原因:3
*/
public class PrintStackTraceDemo01 {
public static void main(String[] args) {
int [] arr={12,23,1};
System.out.println(arr[3]);
}
}
public class ExceptionDemo01 {
public static void main(String[] args) {
test02();
}
private static void test01(){
//创建Throwable对象
Throwable t=new Throwable("空指针异常");
//获得异常信息字符串
System.out.println( t.toString());
//获得异常详细信息字符串
System.out.println(t.getStackTrace());
//追踪异常的根源
t.getMessage();
}
private static void test02(){
test01();
}
}
- 异常分类
- 编译时异常:checked异常。在编译时期,就会检查,如果没有处理异常,则编译失败。 (如日期格式化异常)
- 运行时异常:runtime异常。在运行时期,检查异常,在编译时期,运行异常不会编译器检测(不报错)。(如数学异常)
1.1.3 异常和错误的区别
异常和错误的区别:
- 错误一般是由操作系统反馈给JVM的,无法针对错误进行处理,只能修改错误行的代码。
- 异常一般是JVM反馈给Java程序,可以针对异常进行处理,如果不处理,则结果和错误一样。
异常和错误的判断:
- 根据异常的类名进行判断,如果是以Exception结尾,则是异常,否则就是错误。
常见的异常:
- Java.lang.OutOfMemoryError:Java heap space 堆内存溢出 类全名:异常原因
- java.lang.ArithemeticException:/by zero:数学运行异常
/*
堆内存异常:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at day05Test01.ExceptionDemo02.test01(ExceptionDemo02.java:8)
at day05Test01.ExceptionDemo02.main(ExceptionDemo02.java:5)
数学运算异常:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at day05Test01.ExceptionDemo02.test01(ExceptionDemo02.java:17)
at day05Test01.ExceptionDemo02.main(ExceptionDemo02.java:9)
*/
public class ExceptionDemo02 {
public static void main(String[] args) {
test01();
}
private static void test01(){
/* //定义一个数组,堆内存异常错误
int [] arr=new int [1024 * 1024 * 1024];
System.out.println(arr.length);*/
//数学运行异常
System.out.println(100/0);
}
}
异常的处理
2.1 JVM处理方式
异常处理方法有以下两种:
1.JVM处理方式
- 将异常的信息(异常的类名、异常的原因、异常的位置)打印在控制台
- 退出JVM,终止程序运行
2.手动处理方式:抛出处理、捕获处理
2.2 捕获异常try...catch
如果异常出现的话,会立刻终止程序,所以我们得处理异常:
1. 该方法不处理,而是声明抛出,由该方法的调用者来处理(throws)。
2. 在方法中使用try-catch的语句块来处理异常。
try{ 编写可能产生异常的代码 }catch(异常类型 e){ 处理异常的代码 //处理日志/打印异常信息/继承抛出异常 }
- try:该代码块中编写可能产生异常的代码。
- catch:用来进行某种异常捕获,实现对捕获到的异常进行处理。
- 注意:try和catch都不能单独使用,必须连用。
import java.io.FileNotFoundException;
public class TryCatchDemo {
public static void main(String[] args) {
try {
read("b.txt");
}catch (FileNotFoundException e){
System.out.println(e);
}
System.out.println("over");
}
/*
我们当前的这个方法中有编译器异常
*/
public static void read(String path) throws FileNotFoundException{
if(!path.equals("a.txt")){
//我假设如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw
throw new FileNotFoundException("文件不存在");
}
}
}
多个异常使用捕获又该如何处理呢?
- 多个异常分别处理
- 多个异常一次捕获,多次处理。
- 多个异常一次捕获,一次处理。
- 一般我们使用一次捕获多次处理的方式:
try{ 编写可能会出现异常的代码 }catch(异常类型A e){ //当try中出现A类型异常,就用该catch来捕获 处理异常代码 //记录日志/打印异常信息/继续抛出异常 }catch(异常类型B e){ //当try中出现B类型异常,就用该catch来捕获 处理异常代码 //记录日志/打印异常信息/继续抛出异常
}
- 注意:这种异常处理方式,要求多个catch的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。
- 格式说明
- try代码块:编写可能出现异常的代码,只要try里面有一行代码出现了异常,该行代码后面的代码就不会执行了。
- catch代码块:编写出现异常之后要执行的代码,如果try代码块中的代码没有出现异常,则不会执行该代码块的代码。
- 是否捕获异常只需要捕获Exception异常即可?
- 不是,因为实际开发,有时需要针对不同的异常有不同的处理方式,如果针对所有异常的处理方式都是一样的。则可以直接捕获Exception即可。
public class ExceptionDemo03 {
public static void main(String[] args) {
int a=0;
test01(a);
}
//使用捕获处理异常
private static void test01(int a){
try{
int result=100/a;
System.out.println("result="+result);
//定义数组
int[] arr={1,2,3,4};
System.out.println(arr[3]);
//定义字符串
String str="abc";
System.out.println(str.length());
System.out.println(str.charAt(4));
}catch (ArithmeticException e){
e.getStackTrace();
System.out.println("进来了吗");
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("又进来了吗 ");
}catch (NullPointerException e){
System.out.println("又又进来了吗");
}catch (Exception e){
System.out.println("又又又进来了吗");
}
System.out.println("come here");
}
}
2.3 finally代码块
try{ //可能出现异常的代码 }catch(异常类型 变量名){ //处理异常的代码 }finally{ //不管是否出现异常都要执行代码}
- finally代码块特点:只有代码执行流程进入了try代码块,不管是否出现异常,都会执行该代码块中的代码。
- finally代码块的作用:用来释放资源,比如关闭流,关闭数据库资源。
public class ExceptionDemo04 {
public static void main(String[] args) {
int a=10;
int result=test01(a);
System.out.println("result="+result);
}
//使用捕获处理异常
private static int test01(int a){
if(a != 0){
try {
int result=100/a;
//退出JVM,终止程序运行。
//System.exit(0);
return result;
}catch (ArithmeticException e){
System.out.println("进来了吗");
}finally {
System.out.println("关闭资源数据库");
}
System.out.println("come here");
}
return 0;
}
}
2.4 抛出异常throw和声明异常throws
- throw关键字作用:将异常对象抛给方法调用者并结束当前方法的运行。
- throw关键字的使用格式:throw new 异常类名(“异常信息字符串”);
- throw关键字的使用位置:使用在方法体中
- throws关键字作用:将方法体中可能出现的异常标识出来报告给方法调用者,让方法调用者注意处理异常。
- throws关键字的使用格式:修饰符 返回值类型 方法名(参数列表) throws 异常类名1,异常类名2...{}
- throws关键字的使用位置:使用在方法声明上。
public class ExceptionDemo05 {
public static void main(String[] args) {
int a=0;
int result=test01(a);
System.out.println("result="+result);
System.out.println("come here");
}
private static int test01(int a) throws ArithmeticException,NullPointerException{
try {
int result=100/a;
return result;
}catch (ArithmeticException e){
System.out.println("你的网络不给力哦...");
}
return 0;
}
}
2.5 方法重写异常处理注意点
- 方法重写时异常处理注意事项(针对编译时异常而言)
- 父类方法中没有声明异常时,子类重写方法时也不能声明异常。
- 父类方法中有声明异常时,子类重写方法时可以声明小于等于父类声明的异常。
- 小结:子类重写方法时不能大于父类声明的异常。
2.6 编译时异常和运行时异常
- 什么是编译时异常:除了运行时异常以外的所有异常都是编译时异常。
- 什么是运行异常:只要是RuntimeException或其子类异常都属于运行时异常。
- 编译时异常的特点:
- 方法体中抛出的异常是编译时异常,则要求必须要处理。
- 方法声明中声明的异常是编译时异常,则要求方法调用者一定要处理。
- 运行时异常的特点:
- 方法体中抛出的异常是运行时异常,则可以处理,也可以不处理。
- 方法声明中声明异常是运行时异常,则方法调用者可以处理也可以不处理。
- 为什么Java编译器对运行时异常处理如此松散?
- 因为运行时异常一般是可以通过程序员良好的编程习惯避免的。
3.1自定义异常概述
- 为什么需要自定义异常类: 我们说了Java中不同的异常类,分别表示着某一种具体的异常情况,那么在开发中总是有些异常情况是SUN没有定义 好的,此时我们根据自己业务的异常情况来定义异常类。,例如年龄负数问题,考试成绩负数问题。
在上述代码中,发现这些异常都是JDK内部定义好的,但是实际开发中也会出现很多异常,这些异常很可能在JDK中 没有定义过,例如年龄负数问题,考试成绩负数问题.那么能不能自己定义异常呢?- 异常类如何定义:
- 1. 自定义一个编译期异常: 自定义类 并继承于 java.lang.Exception 。 2. 自定义一个运行时期的异常类:自定义类 并继承于 java.lang.RuntimeException 。
3.2 自定义异常的案例:
1. 在Person类的有参数构造方法中,进行年龄范围的判断。
2. 若年龄为负数或大于200岁,则抛出NoAgeException异常,异常提示信息“年龄数值非法”。
3. 要求:在测试类中,调用有参数构造方法,完成Person对象创建,并进行异常的处理。
public class Person {
private int age;
public Person() {
super();
}
public Person(int age) throws NoAgeException {
setAge(age);
}
public int getAge() {
return age;
}
public void setAge(int age) throws NoAgeException {
//判断年龄是否合法
if(age<0 || age>200){
throw new NoAgeException("你不是地球人,滚回火星去吧...");
}
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
}
/*
自定义异常类
*/
public class NoAgeException extends Exception {
//无参构造
public NoAgeException() {
}
//有参构造
public NoAgeException(String message){
super(message);
}
}
public class ExceptionDemo {
public static void main(String[] args) throws NoAgeException {
//创建Person对象
Person p=new Person();
p.setAge(300);
System.out.println("p");
}
}
- 自定义异常的步骤:
- 创建一个类,类名:XxxException
- 继承官方的异常类:
- RuntimeException:运行时异常
- Exception:编译时异常
- 3.提供构造方法:
- 有参构造
- 无参构造
4.1 并发与并行
- 学习多线程的目的:为了让多个任务能够并行执行,提高程序的执行效率。
- 并行和并发的概念:
- 并发:两个或多个任务在同一时间执行,比如任务A和任务B在18:23:30
- 并发:两个或多个任务在同一时间段执行,比如任务A和任务B在18:23:30到18:25:30执行了。
4.2 线程和进程
- 进程的概念:一个正在运行中的程序就是一个进程。
- 线程的概念:进程中的一个独立的执行路径(执行单元)
- 进程和线程案例:
- 可以理解为进程
- 可以理解为线程
- 进程的作用:用来封装线程,为线程执行任务提供资源(内存资源)
- 线程的作用:用来执行代码的
- 创建线程的方式1:继承Thread类
- 创建一个类继承Thread类
- 重写run方法:将线程任务相关的代码写在该方法中
- 创建Thread子类对象,调用start方法开启线程。
/*
自定义线程
*/
public class MyThread extends Thread {
@Override
public void run(){
for (int i = 0; i < 10; i++) {
System.out.println("run..."+i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
//创建线程对象,相当于招聘一个工人
MyThread t=new MyThread();
// 开启线程:开辟新的执行路径执行run方法的代码
t.start();
// 不要手动调用run方法:不会开启新的执行路径,而是在当前线程执行run方法的代码
// t.run();
for (int i = 0; i < 10; i++) {
System.out.println("main..."+i);
}
}
}