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{
public void function() throws FileNotFoundException{
System.out.println("子类重写的function方法");
}
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);
}
}
}
/*
在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方法中定义线程要执行的任务
public void run() {
//输出100次HelloJava
for(int i = 0; i < 100; i++) {
System.out.println("新线程在输出HelloJava:" + i);
}
}
}
继续阅读

资源分享QQ群
本站是一个IT技术分享社区, 会经常分享资源和教程; 分享的时代, 请别再沉默!
评论