1、
/*
* 异常即是一种意外,是程序运行过程中产生的一种突发(意外)
* 事件,该事件会干扰程序的正常执行,打破程序的正常流程。
*
* 当异常产生时,会创建一个相关异常类的对象,该对象含有异常的
* 相关信息。
* 异常产生时,会在异常的上下文中寻找异常处理程序,如果没有
* 异常处理程序,则异常产生之后的语句将不会得到执行。该异常
* 会向上传播(传播给方法的调用端)。如果传播到main方法里,还
* 未处理该异常,则main方法会将异常传播给JVM,此时,整个
* 线程终止执行。在控制台会打印出异常的相关信息与堆栈的调用
* 轨迹。该轨迹是按照方法调用的逆序打印,即离异常发生地最近
* 的方法会最先打印。
*/
package day12;
public class ExceptionTest {
public static void main(String[] args) {
a();
}
public static void a() {
b();
}
public static void b() {
c();
}
public static void c() {
int x = 5;
int y = 0;
int z = x / y;
System.out.println("x除以y的结果是:");
System.out.println(z);
}
}
2、
异常可以分成以下三种:
受检异常 运行时异常 错误
说明:运行时异常与错误统称为非受检异常。

当异常发生时,我可以采用两种方式进行处理:
捕获异常
抛出异常
说明:受检异常要求程序员在编译时显式处理,而非受检异常则不需要。
3、异常处理
/*
* 异常处理程序(异常处理器)
* try {
* 可能产生异常的程序
* } catch (异常1) {
* 恢复措施
* } catch (异常2) {
* 恢复措施
* } ……
* catch (异常n) {
* 恢复措施
* }
*
* try-catch的三种情况:
* 1 try语句块中没有产生异常。此时try语句块全部执行完毕,
* 之后执行try-catch之后的语句。
* 2 try语句块中产生异常,catch捕获了该异常。
* try中如果产生异常,则此时会创建一个相关异常类的对象,异常之后
* 的语句将不会得到执行。程序会跳转到catch分支,从上到下依次使用
* 异常类对象与每个catch中的异常类型进行匹配,哪一个catch分支
* 匹配成功,则执行哪个catch语句块,此时异常被成功捕获。try-catch
* 之后的语句正常执行。(最多只会执行一个catch分支)
* 3 try语句块中产生异常,catch没有捕获该异常。
* 当try中产生异常时,try异常之后的语句不会得到执行。程序
* 跳转到catch分支进行异常匹配,没有匹配成功,则表示没有捕获
* 该异常(该异常继续存在),则try-catch之后的语句不会得到
* 执行,该异常会继续向上传播(传播给方法的调用端)。
*/
package day12;
public class Try {
public static void main(String[] args) {
try {
int x = 1;
// int y = 10;
int y = 0;
int z = x / y;
// System.out.println(z);
// String s = null;
// s.length();
// System.out.println("dd");
} catch (ArithmeticException e) {
// 打印异常错误的堆栈轨迹
e.printStackTrace();
// 打印异常的信息。
// System.out.println(e.getMessage());
}
System.out.println("try-catch后的语句执行");
}
}
4、finally
/*
* try-catch-finally
* try-catch语句块可以同时使用finally。
* catch与finally都是可选的。但是二者不能同时缺失。
* finally的特征:
* 不管try是否产生异常,也不管catch是否捕获了try中产生
* 的异常,finally都将会得到执行。
* 因为finally总是会得到执行(虚拟机退出的情况例外),所以
* 我们在finally语句块中进行资源的释放是非常合适的。
*
* finally中的返回值会镇压try中的返回值。
*/
package day12;
public class Finally {
public static void main(String[] args) {
try {
// System.out.println("没有产生异常");
// String s = null;
// s.length();
// System.out.println(5 / 0);
// 回收程序
} catch (NullPointerException e) {
// e.printStackTrace();
} finally {
// System.out.println("finally执行了");
}
// for (int i = 0; i < 10; i++) {
// try {
// break;
// } finally {
// System.out.println("finally执行了");
// }
// }
// f();
// try {
// // 退出虚拟机
// System.exit(0);
// } finally {
// System.out.println("finally执行了");
// }
System.out.println(g());
}
public static void f() {
try {
return;
} finally {
System.out.println("finally执行了");
}
}
// 返回的是fianlly中的return值。
public static int g() {
try {
return 1;
} finally {
return 2;
}
}
}
5、
/*
* 捕获异常时,如果多个catch捕获的异常类型存在父子关系,
* 则需要将子类型方法前面,父类型放在后面。因为子类型能够
* 捕获的,父类型都能够捕获,如果父类型的catch放在前面,
* 则子类型的catch永远没有机会得到执行。
*/
package day12;
public class CatchOrder {
public static void main(String[] args) {
try {
} catch (NullPointerException e) {
} catch (RuntimeException e) {
} catch (Exception e) {
}
/*
* try {
*
* } catch(Exception e) {
*
* } catch (RuntimeException e) { //永远没有机会得到执行 }
*/
}
}
6、多重捕获异常
/*
* 多重捕获异常
*
* 当try语句块中,可能会产生多个异常,而多个异常的处理方式
* 又完全相同时,我们就可以使用多重捕获异常。
* 注意:不要使用多个异常的父类来代替多重捕获异常,因为父类
* 会捕获更多的异常(我们意料之外的异常),这可能会隐藏掩盖
* 我们程序的漏洞。
*
* 当使用多重异常捕获时,catch捕获异常的参数将隐式使用final
* 来修饰。
*/
package day12;
public class MultiCatch {
public static void main(String[] args) {
try {
// 可能产生异常的代码
} catch (ArithmeticException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
// 多重捕获
try {
// String s = null;
// s.length();
// System.out.println(1 / 0);
} catch (ArithmeticException | NullPointerException e) {
e.printStackTrace();
// e = null;
}
try {
String s = null;
s.length();
// System.out.println(1 / 0);
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}
7、throws 异常列表
/*
* throws 异常列表
*
* 如果一个方法中可能会抛出受检异常,则要求该异常必须
* 同时声明在方法的异常列表中。对于非受检异常(运行时
* 异常与错误),则不要求声明在方法的异常列表中。
*
* 异常分为三种:
* 1 受检异常(编译时异常)
* 2 运行时异常
* 3 错误
* 运行时异常和错误统称为非受检异常。
*
* 受检异常继承Exception类或其子类。
* (不包括RuntimeException或其子类)
* 运行时异常继承RuntimeException或其子类。
* 错误继承Error类或其子类。
*
* 受检异常与非受检异常的区别:
* 受检异常必须在编译期间就需要明确对其进行处理,
* 而非受检异常则不需要。
*/
package day12;
import java.io.FileNotFoundException;
public class Throws {
public static void main(String[] args) {
}
public void f(int x, int y) throws FileNotFoundException {
if (x < 0) {
throw new NullPointerException();
}
if (y < 0) {
throw new FileNotFoundException();
}
}
// 该方法不会抛出FileNotFoundException(受检异常)
public void g(int x) {
// try {
// if (x < 0) {
// throw new FileNotFoundException();
// }
// } catch(FileNotFoundException e) { }
}
}
8、方法重写的第五条
/*
* 方法重写的第五条要求:
* 子类重写父类的方法,则子类方法不能比父类方法抛出更多
* 的受检异常。(只能与父类相同,或者是父类抛出受检异常的
* 子类异常)。对于非受检异常,则不受限制。
*/
package day12;
public class Override5 {
public static void main(String[] args) {
Override5 o = new Override5();
o.use(new WhiteHorse());
}
public void use(Horse h) {
h.run();
}
/*
* public int x() { throw new NullPointerException(); }
*/
}
class Horse {
public void run() {
}
}
class WhiteHorse extends Horse {
// 错误,子类方法比父类方法抛出了更多的受检异常。
/*
* @Override public void run() throws Exception {
*
* }
*/
@Override
public void run() throws NullPointerException, IllegalArgumentException {
}
}
9、手动抛出异常
/*
* 手动抛出异常 throw
*/
package day12;
public class Throw {
public static void main(String[] args) {
Throw t = new Throw();
t.deal(-1);
}
public void deal(int age) {
if (age <= 0) {
throw new IllegalArgumentException("年龄必须大于0!输入年龄为:" + age);
}
System.out.println("执行了吗?");
// 对年龄进行处理
}
}
10、自定义异常
/*
* 自定义异常
* 为什么要使用自定义异常?
* 1 Java类库提供的异常类不能满足所有人的需要。
* 2 自定义异常可以令我们快速定位问题。
*
* 按照惯例,自定义异常名使用Exception进行结尾。
*/
package day12;
public class SelfException {
public void use() {
SelfException s = new SelfException();
//s.deal(-1);
try {
s.deal(-1);
} catch (NegtiveAgeException e) {
System.out.println("进行异常的处理");
}
}
public void deal(int age) {
if (age <= 0) {
throw new NegtiveAgeException("年龄为负!" + age);
}
System.out.println("年龄合理,进行处理。");
}
}
class NegtiveAgeException extends RuntimeException {
public NegtiveAgeException(String s) {
super(s);
}
public NegtiveAgeException() {
this("年龄为负数,请输入核对!");
}
}
11、异常优势:
使用异常具有如下优势: 可以将正常的代码与异常处理的代码相分离。 可以将异常信息沿着方法调用轨迹向上传播。 异常具有明确的类型与继承体系, 便于分类处理。
补充:
1、捕获异常
使用try(尝试着)去执行可能产生异常的程序,一旦异常发
生,系统会自动创建一个相应的异常类对象,同时终止try的
执行( try语句块异常产生位置之后的代码将不会执行)。
一旦产生异常,将会从上到下去匹配catch中异常类,一旦匹
配成功,则异常对象就会传递给catch参数,执行相应catch
语句块。如果没有匹配成功,则该异常会继续向上抛出给方
法调用端。
catch语句块最多只会执行一个。如果所有方法中都没有合适
的异常处理器,则当前线程终止。
无论try是否抛出异常,也无论catch是否捕获异常, finally
语句块都将在try或catch执行后执行。
catch捕获的异常类型必须是Throwable类型或其子类型。
finally是可选的。 catch也是可选的,但catch与finally不能
同时为空。
2、
常见异常:
1:非受检异常
NullPointerException,ClassCastException,ArrayIndexsOutOfBoundsException,ArithmeticException(算术异常,除0溢出)
2)受检:Exception,FileNotFoundException,IOException,SQLException.

