1.异常
Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError(栈溢出)和OOM(内存溢出)。一般不编写针对性的代码进行处理。
Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。
错误:Error类以及它的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注Exception为父类的分支下的各种异常类。
异常:Exception以及它的子类,代表程序运行时发生的各种不期望发生的事件。可以被Java异常处理机制使用,是异常处理的核心。
Error是系统中的错误,程序员是不能改变的和处理的,一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。因此我们编写程序时不需要关心这类错误。
Exception,也就是我们经常见到的一些异常情况,表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
2.JVM默认处理异常的方式
如果程序出现了问题,我们没有做任何处理,最终JVM 会做默认的处理,处理方式有如下两个步骤:
1.把异常的名称,错误原因及异常出现的位置等信息输出在了控制台
2.程序停止执行(哪里出现异常程序就在哪里停止,下面的代码就不执行)
3.处理异常方式——throws
throws是另一种处理异常的方式,它不同于try...catch...finally,throws仅仅是将函数中可能出现的异常向调用者声明,而自己则不具体处理。
采取这种异常处理的原因可能是:方法本身不知道如何处理这样的异常,或者说让调用者处理更好,调用者需要为可能发生的异常负责。
定义格式:
public void 方法() throws 异常类名 {
}
代码:
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("开始");
// method();
try {
method2();
}catch (ParseException e) {
e.printStackTrace();
}
System.out.println("结束");
}
//编译时异常
public static void method2() throws ParseException {
String s = "2048-08-09";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(s);
System.out.println(d);
}
//运行时异常
public static void method() throws ArrayIndexOutOfBoundsException {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
}
}
注意:如果声明的异常是运行时异常,那么声明的代码可以省略
如果声明的异常是编译时异常,那么声明的代码必须手动写出
4.手动抛出异常——throw
Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要使用人工创建并抛出。
throw 语句必须写在函数中,执行throw 语句的地方就是一个异常抛出点
定义格式:
throw new 异常();
代码:
public class StudentTest {
public static void main(String[] args) {
try {
Student s = new Student();
s.regist(-1001);
System.out.println(s);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
class Student {
private int id;
public void regist(int id) throws Exception {
if (id > 0) {
this.id = id;
} else {
// System.out.println("您输入的数据非法!");
//手动抛出异常对象
// throw new RuntimeException("您输入的数据非法!");
throw new Exception("您输入的数据非法!");
//错误的
// throw new String("不能输入负数");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
5.throws和throw的区别
6.异常处理方式——try-catch
try块中的局部变量和catch块中的局部变量(包括异常变量),以及finally中的局部变量,他们之间不可共享使用。
每一个catch块用于处理一个异常。异常匹配是按照catch块的顺序从上往下寻找的,只有第一个匹配的catch会得到执行。匹配时,不仅运行精确匹配,也支持父类匹配,因此,如果同一个try块下的多个catch异常类型有父子关系,应该将子类异常放在前面,父类异常放在后面,这样保证每个catch块都有存在的意义。
定义格式:
try {
可能出现异常的代码;
} catch(异常类名 变量名) {
异常的处理代码;
}
代码:
public class ExceptionDemo01 {
public static void main(String[] args) {
System.out.println("开始");
method();
System.out.println("结束");
}
public static void method() {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
System.out.println("这里能够访问到吗");
} catch (ArrayIndexOutOfBoundsException e) {
// System.out.println("你访问的数组索引不存在,请回去修改为正确的索引");
e.printStackTrace();
}
}
}
7.Throwable成员方法
常用方法:
方法名 | 说明 |
---|---|
public String getMessage() | 返回此 throwable 的详细消息字符串 |
public String toString() | 返回此可抛出的简短描述 |
public void printStackTrace() | 把异常的错误信息输出在控制台 |
代码:
public class ExceptionDemo02 {
public static void main(String[] args) {
System.out.println("开始");
method();
System.out.println("结束");
}
public static void method() {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[3]); //new ArrayIndexOutOfBoundsException();
System.out.println("这里能够访问到吗");
} catch (ArrayIndexOutOfBoundsException e) { //new ArrayIndexOutOfBoundsException();
// e.printStackTrace();
//public String getMessage():返回此 throwable 的详细消息字符串
// System.out.println(e.getMessage());
//Index 3 out of bounds for length 3
//public String toString():返回此可抛出的简短描述
// System.out.println(e.toString());
//java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
//public void printStackTrace():把异常的错误信息输出在控制台
e.printStackTrace();
// java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
}
}
}
8.编译时异常和运行时异常的区别
-
编译时异常
- 都是Exception类及其子类
- 必须显示处理,否则程序就会发生错误,无法通过编译
-
运行时异常
- 都是RuntimeException类及其子类
- 无需显示处理,也可以和编译时异常一样处理
9.自定义异常
如果要自定义异常类,则扩展Exception类即可,因此这样的自定义异常都属于检查异常(checked exception)。如果要自定义非检查异常,则扩展自RuntimeException。
按照国际惯例,自定义的异常应该总是包含如下的构造函数:
一个无参构造函数
一个带有String参数的构造函数,并传递给父类的构造函数。
一个带有String参数和Throwable参数,并都传递给父类构造函数。
一个带有Throwable 参数的构造函数,并传递给父类的构造函数。
自定义异常的构建:
继承Exception
public class MyException extends Exception {
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
public MyException(Throwable cause) {
super(cause);
}
}
使用自定义异常
如果自定义异常是为了提示,在使用的时候,一定要用try..catch,不要直接用throw往外抛。
public class Test {
public static void main(String[] args) {
A a = new A();
try {
a.show(-2);
} catch (MyException e) {
System.out.println(e.getMessage());
}
}
}
class A {
public void show(int num) throws MyException {
if (num < 0) {
MyException me = new MyException("异常:" + num + "不是正数");
throw me;//抛出异常,结束方法show()的执行
}
System.out.println(num);
}
}
应用:
自定义异常类:
public class ScoreException extends Exception {
public ScoreException() {}
public ScoreException(String message) {
super(message);
}
}
老师类:
public class Teacher {
public void checkScore(int score) throws ScoreException {
if(score<0 || score>100) {
// throw new ScoreException();
throw new ScoreException("你给的分数有误,分数应该在0-100之间");
} else {
System.out.println("成绩正常");
}
}
}
测试类:
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入分数:");
int score = sc.nextInt();
Teacher t = new Teacher();
try {
t.checkScore(score);
} catch (ScoreException e) {
e.printStackTrace();
}
}
}