异常:异常就是Java程序在运行过程中出现的错误。
异常由来:问题也是现实生活中一个具体事务,也可以通过java 的类的形式进行描述,并封装成对象。其实就是Java对不正常情况进行描述后的对象体现。
异常分类图解:
Throwable 1--Error 严重问题,我们不处理。 2--Exception (1)--RuntimeException 运行期异常,我们需要修正代码 (2)--非RuntimeException 编译期异常,必须处理的,否则程序编译不通过
public class ExceptionTest1 {
public static void main(String[] args) {
int a=10;
int b=0;
System.out.println(a/b);
System.out.println("通过!");
}
}
这是一个除数为0造成的典型的运行异常
这是Java虚拟机默认的处理,将异常的名称,原因,出现的问题输出在控制台
同时也中断程序
try...catch...finally 自己编写处理代码,后面的程序可以继续执行 throws 抛出,把自己处理不了的,在方法上声明,告诉调用者,这里有问题
注意:try里面的代码越少越好
将问题包在try中,程序可以运行,但是catch里必须有代码,不然只能是隐藏问题而不是处理异常
public class ExceptionTest1 {
public static void main(String[] args) {
int a=10;
int b=0;
try{
System.out.println(a/b);
}catch(ArithmeticException Ex){
System.out.println("异常!除数不能为0");
}
System.out.println("通过!");
}
}
//多个异常的情况
public class ExceptionTest1 {
public static void main(String[] args) {
int a=10;
int b=0;
int i[]={0,1,2};
try{
System.out.println(i[3]);
System.out.println(a/b);
}catch(ArithmeticException Ex){
System.out.println("异常!除数不能为0");
}catch(ArrayIndexOutOfBoundsException Ex){
System.out.println("异常!访问无效!");
}
System.out.println("通过!");
}
}
我们可以看到并没有输出第一个catch中的异常处理语句,这是因为一旦try 里出了问题就会把这个异常抛出去到 catch 中匹配异常,匹配到之后执行 catch 里的语句,然后结束 try...catch 在执行下面的语句
public class ExceptionTest1 {
public static void main(String[] args) {
int a=10;
int b=0;
int i[]={0,1,2};
try{
System.out.println(i[3]);
System.out.println(a/b);
System.out.println("未知的异常!");
}catch(ArithmeticException Ex){
System.out.println("异常!除数不能为0");
}catch(ArrayIndexOutOfBoundsException Ex){
System.out.println("异常!访问无效!");
}catch(Exception Ex){//Exception可以匹配所有的异常类型
System.out.println("异常!未知!");
}
System.out.println("通过!");
}
}
在catch()中我们应该写异常类型,能明确的尽量明确以节约资源,不能明确的也可以写 Exception
注意:Exception 可以匹配所有异常,所有不能写在前面,否则后面的无效,所以,平级关系的异常前后顺序无所谓,父子关系的异常父类必须在后面。
try...catch...finally的格式变形 * A:try...catch...finally * B:try...catch * C:try...catch...catch... * D:try...catch...catch...finally * E:try...finally 这种做法的目前是为了释放资源。
JDK7的新特性,可以再catch中将多个异常用 | 隔开
public class ExceptionTest1 {
public static void main(String[] args) {
int a=10;
int b=0;
int i[]={0,1,2};
try{
System.out.println(i[3]);
System.out.println(a/b);
System.out.println("未知的异常!");
}catch(ArithmeticException | ArrayIndexOutOfBoundsException Ex){
System.out.println("异常!");
}
System.out.println("通过!");
}
}
这种方法的局限性,只能给出一个解决方案,多个异常要是平级关系
编译期异常和运行期异常的区别? 编译期异常 必须要处理的,否则编译不通过 运行期异常 可以不处理,也可以处理
getMessage public String getMessage() 返回此 throwable 的详细消息字符串。返回:此 Throwable 实例(可以为 null)的详细消息字符串。
toString public String toString() 返回此 throwable 的简短描述。如果此
Throwable
对象是利用非空详细消息字符串创建的,则结果是三个字符串的串联:
getMessage()
方法的结果 如果此 Throwable
对象利用 null 详细消息字符串创建,则返回此对象的实际类的名称。覆盖:类 Object
中的 toString
返回:该 throwable 的字符串表示形式。
printStackTrace
public void printStackTrace()
将此 throwable 及其追踪输出至标准错误流。此方法将此 Throwable
对象的堆栈跟踪输出至错误输出流,作为字段 System.err
的值。输出的第一行包含此对象的 toString()
方法的结果。剩余行表示以前由方法 fillInStackTrace()
记录的数据。此信息的格式取决于实现,但以下示例是最常见的:
java.lang.NullPointerException
at MyClass.mash(MyClass.java:9)
at MyClass.crunch(MyClass.java:6)
at MyClass.main(MyClass.java:3)
本示例通过运行以下程序生成:
class MyClass {
public static void main(String[] args) {
crunch(null); }
static void crunch(int[] a) {
mash(a); }
static void mash(int[] b) {
System.out.println(b[0]);
}
}
对于带初始化非空 cause 的 throwable 的追踪,通常应该包括 cause 的追踪。此信息的格式取决于实现,但以下示例是最常见的:
HighLevelException: MidLevelException: LowLevelException
at Junk.a(Junk.java:13)
at Junk.main(Junk.java:4)
Caused by: MidLevelException: LowLevelException
at Junk.c(Junk.java:23)
at Junk.b(Junk.java:17)
at Junk.a(Junk.java:11)
... 1 more Caused by: LowLevelException
at Junk.e(Junk.java:30)
at Junk.d(Junk.java:27)
at Junk.c(Junk.java:21)
... 3 more
注意,存在包含字符 "..." 的行。这些行指示此异常的椎栈跟踪的其余部分匹配来自异常(由 "enclosing" 异常引起)的堆栈跟踪底部的指定数量的帧。这种简便方法可以大大缩短通常情况下的输出长度,这里抛出了包装的异常,其方法与捕获“作为 cause 的异常”的方法相同。上述示例通过运行以下程序生成:
public class Junk {
public static void main(String args[]) {
try {
a();
} catch(HighLevelException e) {
e.printStackTrace();
}
}
static void a() throws HighLevelException {
try {
b();
} catch(MidLevelException e) {
throw new HighLevelException(e);
}
} static void b() throws MidLevelException {
c();
}
static void c() throws MidLevelException {
try {
d();
} catch(LowLevelException e) {
throw new MidLevelException(e);
}
} static void d() throws LowLevelException {
e();
}
static void e() throws LowLevelException {
throw new LowLevelException();
}
}
class HighLevelException extends Exception {
HighLevelException(Throwable cause) { super(cause);
} } class MidLevelException extends Exception {
MidLevelException(Throwable cause) { super(cause);
}
} class LowLevelException extends Exception {
}
public class ExceptionTest1 {
public static void main(String[] args) {
int a=10;
int b=0;
int i[]={0,1,2};
try{
System.out.println(i[3]);
}catch(Exception Ex){
System.out.println(Ex.getMessage()); //异常的消息字符串
System.out.println(Ex.toString()); //异常消息简单描述
Ex.printStackTrace(); //获取异常类名和异常信息,以及异常出现在程序中的未知,void,把信息输出在控制台
}
System.out.println("通过!");
}
}
定义功能方法时,需要把出现的问题暴露出来让调用者去处理。那么就通过throws在方法上标识。
public void show() throws ParseException {
String s="2017-07-23";
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d=sdf.parse(s);
System.out.println(sdf.format(d));
}
try {
d.show();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
注意:编译期异常抛出将来调用者必须处理
运行期异常抛出,将来调用者可以不处理
throws后也可以跟多个异常
在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。这时抛出的应该是异常的对象。
int a=10;
int b=0;
if(b==0){
throw new ArithmeticException();
}else{
System.out.println(a/b);
}
throws和throw的区别 throws 用在方法声明后面,跟的是异常类名 可以跟多个异常类名,用逗号隔开 表示抛出异常,由该方法的调用者来处理 throws表示出现异常的一种可能性,并不一定会发生这些异常 throw 用在方法体内,跟的是异常对象名 只能抛出一个异常对象名 表示抛出异常,由方法体内的语句处理 throw则是抛出了异常,执行throw则一定抛出了某种异常
如果该功能内部可以将问题处理,用try,如果处理不了,交由调用者处理,这是用throws 区别: 后续程序需要继续运行就try 后续程序不需要继续运行就throws 举例: 感冒了就自己吃点药就好了,try 吃了好几天药都没好结果得了H7N9,那就的得throws到医院 如果医院没有特效药就变成Error了
特点:
被finally控制的语句体一定会执行 特殊情况:在执行到finally之前jvm退出了(比如System.exit(0))
作用:用于释放资源
String s="2017-07-23";
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d=null;
try{
d=sdf.parse(s);
}catch(ParseException ex){
ex.printStackTrace();
}finally{
System.out.println("!这里的语句一定会执行!");
}
System.out.println(d);
final,finally和finalize的区别 final:最终的意思,可以修饰类,成员变量,成员方法 修饰类,类不能被继承 修饰变量,变量是常量 修饰方法,方法不能被重写 finally:是异常处理的一部分,用于释放资源。 一般来说,代码肯定会执行,特殊情况:在执行到finally之前jvm退出了 finalize:是Object类的一个方法,用于垃圾回收 如果catch里面有return语句,finally里面的代码还会执行吗? 如果会,是在return前,还是return后。 会。前。 准确的说,应该是在中间。
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
} catch (ArithmeticException e) {
a = 30;
return a;
/*
* return a在程序执行到这一步的时候,这里不是return a而是return 30;这个返回路径就形成了。
*它发现后面还有finally,所以继续执行finally的内容,a=40
* 再次回到以前的返回路径,继续走return 30;
*/
} finally {
a = 40;
return a;//如果这样结果就是40了。
}
return a; //这里的语句不会执行
Java中定义了很多常见的异常类,但是在实际运行中也需要我们自己定义异常类。
自定义的异常类需要继承自继承自Exception或者RuntimeException,只需要提供无参构造和一个带参构造即可
//自定义异常类
public class MyException extends Exception {
public MyException() {
}
public MyException(String message) {
super(message);
}
}
//老师类
public class Teacher {
public void check(int score) throws MyException {
if (score > 100 || score < 0) {
throw new MyException("分数必须在0-100之间");
} else {
System.out.println("分数没有问题");
}
}
}
//主方法
import java.util.Scanner;
public class StudentDemo {
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.check(score);
} catch (MyException e) {
e.printStackTrace();
}
}
}
如果继承自RuntimeException
public class Teacher {
public void check(int score) throws MyException {
//针对MyException继承自RuntimeException
public void check(int score) {
if (score > 100 || score < 0) {
throw new MyException();
} else {
System.out.println("分数没有问题");
}
}
}
public class MyException extends RuntimeException {
}
异常的注意 A:父的方法有异常抛出,子的重写方法在抛出异常的时候必须要小于等于父的异常 B:父的方法没有异常抛出,子的重写方法不能有异常抛出 C:父的方法抛出多个异常,子的重写方法必须比父少或者小