第三章:集合03
一:什么是异常,异常的作用是什么??
程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常。异常发生时,是任程序自生自灭,立刻退出终止。在Java中即,Java在编译或运行或者运行过程中出现的错误。
异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。
二:java异常分类
异常的根接口Throwable,其下有2个子接口,Error和Exception。
- Error:指的是JVM错误,这时的程序并没有执行,无法处理;(不可预料的)
- Exception:指的是程序运行中产生的异常,用户可以使用处理格式处理。(可预料的)
- Exception又可分为 编译异常与运行异常。
三:异常的使用及执行流程
1. JVM默认处理异常的方式
在控制台答应错误信息,并终止程序。
public class ExceptionTest01 {
public static void main(String[] args) {
int a = 10;
int b = 0;
//当程序执行到这里时JVM会new一个异常对象 new ArithmeticException("/ by zero")
//并且JVM将new的异常对象跑出,打印到输出信息控制台上
int c = a / b;
System.out.println(a + "/" + b + "=" + c);
}
}
2. 开发中异常的处理方式
- try…catch(finally):捕获,自己处理。
try…catch、try…catch…finally、try…finally
try{
可能会发生的异常
}catch(异常类型 异常名(变量)){
针对异常进行处理的代码
}catch(异常类型 异常名(变量)){
针对异常进行处理的代码
}finally{
释放资源代码;
}
- catch 不能独立于 try 存在。
- catch里面不能没有内容
- 在 try/catch 后面添加 finally 块并非强制性要求的。
- try 代码后不能既没 catch 块也没 finally 块。
- try里面越少越好。
- try, catch, finally 块之间不能添加任何代码。
- finally里面的代码最终一定会执行(除了JVM退出)
- 如果程序可能存在多个异常,需要多个catch进行捕获。
- 异常如果是同级关系,catch谁前谁后没有关系,如果异常之间存在上下级关系,上级需要放在后面
-
throws:抛出,交给调用者处理。
public class ExceptionTest05 { //第一种处理方式:在方法声明上继续使用:throws,来完成异常的继续上抛。抛给调用者 /* public static void main(String[] args) throws ClassNotFoundException { doSome(); } */ //第二种处理方式:try...catch 进行捕捉。 public static void main(String[] args) { try { doSome(); }catch (ClassNotFoundException e){ e.printStackTrace(); } } public static void doSome()throws ClassNotFoundException{ System.out.println("doSome!!!!"); } }
3. throw和throws的区别?
- throw:指的是在方法中人为抛出一个异常对象(这个异常对象可能是自己实例化或者抛出已存在的);
- throws:在方法的声明上使用,表示此方法在调用时必须处理异常。
4. Error与Exception的区别:
- Error(错误)是系统中的错误,程序员是不能改变的和处理的,是在程序编译时出现的错误,只能通过修改程序才能修正。一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。
- Exception(异常)表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
5. 异常的常用方法:
-
getMessage() 获取异常描述信息
-
printStackTrace() 打印堆栈信息
public class Test01 { public static void main(String[] args) { NullPointerException e = new NullPointerException("空指针异常"); System.out.println(e.getMessage()); e.printStackTrace(); } }
6. 如何自定义异常
第一种表现形式
/*
1.SUN提供的JDK内置的异常肯定是不够用的。在实际开发中,有很多业务,
这些业务出现异常之后,JDK中都是没有的。和业务挂钩的。
2.java中如何自定义异常
两步:
第一步:编写一个类继承Exception或者RuntimeException
第二步:提供两个构造方法,一个无参数的,一个带有String参数的
*/
public class MyException extends Exception {
// 编译时异常
public MyException(){
}
public MyException(String s){
super(s);
}
}
public class Test01 {
public static void main(String[] args) {
//创建异常对象
MyException e = new MyException("用户名不能为空");
//打印异常信息
e.printStackTrace();
//获取异常描述信息
System.out.println(e.getMessage());
}
}
第二种表现形式
/*编写程序,使用一维数组,模拟栈数据结构
要求;
1.这个栈可以存储java中任何应用类型的数据
2.在栈中提供push方法模拟压栈。(栈满了,要有提示信息)
3.在栈中提供pop方法模拟弹栈. (栈空了,要有提示信息)
4.编写一个测试程序,new栈对象,调用push pop方法模拟压栈,弹栈的动作
5.假设栈的默认初始化容量是10
*/
public class MyStack{
//向栈中存储元素,可以使用一维数组模拟。存到栈中,就表示存到数组中。
//为什么选择Object类型的数组,因为栈中存储的是任意数据类型,而Object是任意数据类型的父类
private Object[] elements;
private int index; //栈针
//初始化
public MyStack() {
this.elements = new Object[10];
this.index = -1;
}
//压栈方法
public void push(Object obj) throws MyStackOperationException {
if (this.index >= this.elements.length-1){
// System.out.println("压栈失败!!!!栈满了");
// return;
//创建异常异常
/*
MyStackOperationException e = new MyStackOperationException("压榨失败,栈已满");
throw e;
*/
//手动跑出异常
throw new MyStackOperationException("压榨失败,栈已满");
}
else {
this.index++;
this.elements[index] = obj;
System.out.println("压栈成功");
}
}
public void pop() throws MyStackOperationException {
if(this.index < 0){
// System.out.println("弹栈失败!!!!!栈空了");
// return;
throw new MyStackOperationException("弹栈失败,栈已空");
}
else {
this.elements[index] = null;
index--;
System.out.println("弹栈成功");
}
}
public Object[] getElements() {
return elements;
}
public void setElements(Object[] elements) {
this.elements = elements;
}
}
/*
栈操作异常
*/
public class MyStackOperationException extends Exception{
public MyStackOperationException(){
}
public MyStackOperationException(String s){
super(s);
}
}
public class Test02 {
public static void main(String[] args) {
MyStack stack = new MyStack();
//压榨
try {
stack.push(1);
stack.push(1);
stack.push(1);
stack.push(1);
stack.push(1);
stack.push(1);
stack.push(1);
stack.push(1);
stack.push(1);
stack.push(1);
stack.push(1);
} catch (MyStackOperationException e) {
System.out.println(e.getMessage());
}
try {
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
stack.pop();
} catch (MyStackOperationException e) {
System.out.println(e.getMessage());
}
}
}
7. finally和return
/*
finally面试题
*/
public class finallyTest04 {
public static void main(String[] args) {
int retValue = m();
System.out.println(retValue);//100
}
public static int m(){
/*
java语法规则(有一些规则是不能被破坏的,一旦这么说了,就必须这么做!!!)
java语法有这样一条规则:
方法体中的代码必须遵守自上而下顺序依次逐行执行(亘古不变的语法)
java海油一条语法规则:
return语句一旦执行,整个方法必须结束(亘古不变的语法)
*/
int i = 100;
try {
//这行代码出现在 int i = 100;的下面,所以最终结果必须返回100
//return语句还必须保证是最后执行的,一旦执行,整个方法结束。
return i;
}finally {
i++;
System.out.println("i="+i);
}
}
}