您的位置:首页 > 职场人生

黑马程序员—————Java基础--------异常

2015-08-25 17:45 531 查看
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! ------- 异常异常的概述(个人理解):我们在编写程序的时候在很多时候,可能会有好多问题存在,为了将来方便的表示这些问题的原因,类型,位置,Java就提供了异常对象供我们使用。在别的地方看到的例子,觉得描述的挺好,就拿来帮助理解:流水线上的产品,前面一直都很顺利,到了某个环节发生了问题,产品就做不下去了,要人为的去检查哪儿出了错误,对于不同的错误需要用不同的解决方案,不同的解决方案在异常中就可以体现。其实异常就是程序中出现了不正常的情况。这个问题按照面向对象思想进行描述,并封装成了对象。因为问题的产生有产生的原因、有问题的名称、有问题的描述等多个属性信息存在。当出现多属性信息最方便的方式就是将这些信息进行封装。异常就是java按照面向对象的思想将问题进行对象封装。这样就方便于操作问题以及处理问题。出现的问题有很多种,比如脚标越界,空指针等都是。就这些问题进行分类,而且这些问题都有共性内容。比如:每一个问题都有名称,同时还有问题描述的信息,问题出现的位置,所以可以不断的向上抽取,形成了异常体系。-------java.lang.Throwable:Throwable:可抛出的。|--Error: (严重)错误,一般情况下,不编写针对性的代码进行处理,通常是jvm发生的,需要对程序进行修正。|--Exception:(不严重)异常,可以有针对性的处理方式 :|--- 编译期间:非RuntimeException的,这个是需要我们处理的。|--- 运行期间:RuntimeException,这个是不需要我们处理的,需要修改代码。无论是错误还是异常,它们都有具体的子类体现每一个问题,它们的子类都有一个共性,就是都以父类名作为子类的后缀名。
public class ExceptionDemo {
public static void main(String[] args) {
// 运行时期
int a = 10;
int b = 0;
System.out.println(a / b);

// 编译时期
// FileInputStream fis = new FileInputStream("a.txt");
}
}
如果在编写程序的过程中出现了问题,我们自己没有处理,jvm会采用自动的处理方式:它会把异常的类型,原因,位置直接显示在控制台,后面的代码是不能执行的。那么,如果程序有异常,怎么解决呢?A:编写处理代码 基本格式:try{可能发生问题的代码。}catch(异常类名 变量名){异常处理代码;}finally{释放资源的代码;}注意:一旦有一次发生,就会立马执行catch里面的代码。变形格式:try...catchtry...catch...catchtry...catch...catch...finallytry...finallyJDK7针对多个catch进行了优化:catch(异常1 | 异常2 | 异常3 ... 变量){} 注意:这些异常必须是平级关系。 和try...catch...catch的不同点是:JDK7的这种方案是必须平级关系,不能有子父关系。而try...catch...catch父亲放最后是可以的。B:抛出处理用throws关键字在方法上声明(抛出)。下面是代码中遇到的各种异常情况:1)一个代码中,有多个问题,怎么解决呢?
/*
* 一个代码中,有多个问题,怎么解决呢?
* A:一个个用异常处理方案解决。
* B:针对所有问题,写一个try...catch代码。
* 		try{}catch(){}catch(){}...
* 注意:在异常处理中,一旦try里面有问题了。就直接跳到catch里面执行。
*/
public class ExceptionDemo2 {
public static void main(String[] args) {
// method1();  // 针对每一个异常写一个try...catch代码。

method2();      //一个个用异常处理方案解决。
}

public static void method2() {
try {
//错误类型: ArithmeticException
int a = 10;
// int b = 0;
int b = 2;
System.out.println(a / b);

// 错误类型:ArrayIndexOutOfBoundsException
int[] arr = { 1, 2, 3 };
System.out.println(arr[3]);

// 继续操作
System.out.println("over");
} catch (ArithmeticException ae) {
System.out.println("除数不能为0");
} catch (ArrayIndexOutOfBoundsException ae) {
System.out.println("数组越界异常");
}
}

// 针对每一个异常写一个try...catch代码。
public static void method1() {
// ArithmeticException
int a = 10;
int b = 0;
try {
System.out.println(a / b);
System.out.println("hello");
} catch (ArithmeticException ae) {
System.out.println("除数不能为0");
}

// ArrayIndexOutOfBoundsException
int[] arr = { 1, 2, 3 };
try {
System.out.println(arr[3]);
} catch (ArrayIndexOutOfBoundsException ae) {
System.out.println("数组越界异常");
}
// 继续操作
System.out.println("over");
}
}
A:如果把method2()先注释掉,编译后打出的结果为:为什么没有打出Hello? 这是因为运行到System.out.println(a / b);时,程序出现了错误,然后就会直接跳到catch里面的代码执行,看看是否是ArithmeticException这个问题,判断之后发现是,就执行了System.out.println("除数不能为0");B:如果把method1()先注释掉,编译后打出的结果为:为什么只打出了这两个呢? 接下来一块分析一下,程序走到System.out.println(arr[3]);时,发现索引越界了,于是直接直接跳到catch里面的代码执行,发现第一个不符合,就跳到下一个catch接着判断,符合,于是就执行了第二个catch里面的代码,System.out.println("数组越界异常");2)针对多个异常,写一个try的代码,catch里面会不会有顺序问题呢?下面咱们用一个代码来测试一下
public static void main(String[] args) {
method1();
// method2();
// method3();
}

public static void method3() {
try {
// ArithmeticException
int a = 10;
// int b = 0;
int b = 2;
System.out.println(a / b);

// ArrayIndexOutOfBoundsException
int[] arr = { 1, 2, 3 };
// System.out.println(arr[3]);
System.out.println(arr[2]);

// 这里又出现了一个问题,这里很明显是一个空指针问题。
// 假设我们忘了,也就是说我们不知道这是一个什么异常。
// 怎么处理呢?
String s = null;
System.out.println(s.length());

// 继续操作
System.out.println("over");
} catch (Exception e) {
System.out.println("空指针问题");
}
// catch (ArrayIndexOutOfBoundsException ae) {
// System.out.println("数组越界异常");
// } catch (ArithmeticException ae) {
// System.out.println("除数不能为0");
// }
}

public static void method2() {
try {
// ArithmeticException
int a = 10;
// int b = 0;
int b = 2;
System.out.println(a / b);

// ArrayIndexOutOfBoundsException
int[] arr = { 1, 2, 3 };
// System.out.println(arr[3]);
System.out.println(arr[2]);

// 这里又出现了一个问题,这里很明显是一个空指针问题。
// 假设我们忘了,也就是说我们不知道这是一个什么异常。
// 怎么处理呢?
String s = null;
System.out.println(s.length());

// 继续操作
System.out.println("over");
} catch (Exception e) {
System.out.println("空指针问题");
}
}

public static void method1() {
try {
//第一部分
// ArithmeticException
int a = 10;
int b = 0;
//int b = 2;
System.out.println(a / b);

//第二部分
// ArrayIndexOutOfBoundsException
int[] arr = { 1, 2, 3 };
System.out.println(arr[3]);
//System.out.println(arr[2]);

//第三部分
// 这里又出现了一个问题,这里很明显是一个空指针问题
// 假设我们忘了,也就是说我们不知道这是一个什么异常。// 怎么处理呢?
//String s = null;
//System.out.println(s.length());
// 继续操作
System.out.println("over");
}
catch (ArrayIndexOutOfBoundsException ae) {
System.out.println("数组越界异常");
} catch (ArithmeticException ae) {
System.out.println("除数不能为0");
//
} catch (Exception e) {
//System.out.println("空指针问题");
}
}
在上面程序中,A:如果我们把method2();method3();都先注释掉,打印的结果会是什么呢?为什么程序中System.out.println(arr[3]);肯定会出错,而没有打印“数组越界异常”呢?这是因为程序执行到System.out.println(a / b);时,发现除数为0,就直接跳到下面catch里面找,知道最后一个catch里面符合,于是就打印出"除数不能为0",程序结束,而没有再看其他的代码。B:如果把程序的第三部分放开,第一、二部分分别把错误的注释掉,运行会出错,但是如果我们不知道这个是什么错,可以直接抛Exception,编译之后发现程序没有出错,如果上面两部分错误部分没有注释掉,也可以把上面两个catch全删了,编译之后也不会出错,为什么呢?因为通过查API,我们发现Exception下面有好多子类,每个子类又有好多子类,抛Exception,程序会在Exception里面找,找到符合的错误,就会往下执行,这也体现了面向对象的多态。其实好多时候,如果你知道程序是什么错误,就不要懒省事抛Exception,因为这样使效率变低,不可取。C:如果把method1();method2();都先注释掉,结果会是什么呢?程序会直接出错,而把划红线的两个catch注释掉之后,就没问题了,这是为什么呢?因为Exception是下面两个的父类。综上ABC三种情况,可以得出以下结论(很重要哦~~):针对多个异常,写一个try的代码,catch里面会不会有顺序问题呢?如果异常是平级关系,没有顺序问题。  如果异常存在着子父关系,父一定要放在最后。异常处理中JDK7的新特性JDK7新特性:多个catch用一个catch替代。不是说多个catch的内容,用一个Exception处理。格式:catch(异常1 | 异常2 | 异常3 ... 变量名){} 下面把上面的代码改进一下,大家就理解啦~~
/*
* JDK7新特性:多个catch用一个catch替代。 不是说多个catch的内容,用一个Exception处理。
* 格式:
* 		catch(异常1 | 异常2 | 异常3 ... 变量名){}
*/
public class ExceptionDemo4 {
public static void main(String[] args) {
// method();
method2();
}

private static void method2() {
try {
// ArithmeticException
int a = 10;
// int b = 0;
int b = 2;
System.out.println(a / b);

// ArrayIndexOutOfBoundsException
int[] arr = { 1, 2, 3 };
// System.out.println(arr[3]);
System.out.println(arr[2]);

// 这里又出现了一个问题,这里很明显是一个空指针问题。
// 假设我们忘了,也就是说我们不知道这是一个什么异常。
// 怎么处理呢?
String s = null;
System.out.println(s.length());

// 继续操作
System.out.println("over");
} catch (ArrayIndexOutOfBoundsException | ArithmeticException
| NullPointerException ae) {
System.out.println("这里出问题了");
}
}

private static void method() {
try {
// ArithmeticException
int a = 10;
// int b = 0;
int b = 2;
System.out.println(a / b);

// ArrayIndexOutOfBoundsException
int[] arr = { 1, 2, 3 };
// System.out.println(arr[3]);
System.out.println(arr[2]);

// 这里又出现了一个问题,这里很明显是一个空指针问题。
// 假设我们忘了,也就是说我们不知道这是一个什么异常。
// 怎么处理呢?
String s = null;
System.out.println(s.length());

// 继续操作
System.out.println("over");
} catch (ArrayIndexOutOfBoundsException ae) {
System.out.println("数组越界异常");
} catch (ArithmeticException ae) {
System.out.println("除数不能为0");
} catch (NullPointerException ne) {
System.out.println("空指针问题");
}
}
}
把method();注释掉,重写一个method2();我们发现没有报错,这就是JDK7的新特性,使程序变得更简明。Throwable的几个重要方法Throwable中的方法:public String getMessage():返回的是异常的消息字符串。public String toString():返回异常的简单描述信息。全路径类名 : 消息字符串public void printStackTrace():把错误信息显示在控制台。(最重要)附一个代码帮助理解:
public class ExceptionDemo {
public static void main(String[] args) {
int a = 10;
int b = 0;
try {
System.out.println(a / b); // 一旦发生问题,在这里其实就产生了一个ArithmeticException对象。
// 然后,拿着这个对象,去和catch里面的类型进行匹配。如果有,就赋值。
// new ArithmeticException()
} catch (ArithmeticException ae) { // ArithmeticException ae = new <span style="font-family: SimSun;">ArithmeticException();</span>

// System.out.println("除数不能为零");
// 通过分析,那么,ae是一个对象了
// / by zero
// System.out.println(ae.getMessage());

// java.lang.ArithmeticException: / by zero
// System.out.println(ae.toString());

// 实际开发中,获取到异常后,<span style="font-family: SimSun;">会</span><span style="font-family: SimSun;">自动判断是某种异常,然后一个错误信息处理界面。</span>
ae.printStackTrace();
}

System.out.println("over");
}
}
运行后结果为:程序中的错误信息会显示在控制台上,然后继续执行以下面的代码。finally的使用 1)基本格式:try{可能有问题的代码}catch(异常类名 变量名){处理方案。变量名.printStackTrace();}finally{释放资源。(数据库,IO)}2)特点:finally:里面代码永远会执行。
public class FinallyDemo {public static void main(String[] args) {int a = 10;int b = 0;try {System.out.println(a / b);} catch (ArithmeticException ae) {ae.printStackTrace();} finally {System.out.println("over");}}}
上面的代码运行后会打印出over,这时有人会问,就算不写finally,over也会打印出来啊,finally有什么用啊? 有时候下面的代码可能和try catch里面的有关,可能是一个整体,加上finally,程序执行完try catch之后,就会直接执行finally里面的,增强程序的可读写。在这儿说一下相关的面试题:1、finally里面的代码真的永远会执行吗? 会永远执行。但是有一个特殊情况:在代码执行到finally之前,jvm就退出了。2、假如在catch里面有return语句,请问finally里面的代码还会执行吗?如果执行,是在return前,还是return后?回答之前,先看一个代码:
public class FinallyTest {public static void main(String[] args) {int result = method3();System.out.println(result);}private static int method3() {int a = 10;try {System.out.println(a / 0);System.out.println("a1:" + a);} catch (ArithmeticException ae) {System.out.println("a2:" + a); // a2:10a = 20;return a; //这个时候,在内存中就会有一个路径产生,该路径返回值是20.//但是,它看到了finally代码块,所以,继续执行finally里面的内容//当finally里面结束后,会回到以前的执行路径。} finally {System.out.println("a3:" + a); // a3:20a = 30;//return a;}return a;}
运行后结果为:从结果中我们可以看出:finally里面的代码会执行,而且是在return前执行。但是为什么呢?在内存中就会有一个路径产生,该路径返回值是20.但是,它看到了finally代码块,所以,继续执行finally里面的内容,当finally里面结束后,会回到以前的执行路径。但是看下面这种情况:把finally里的return语句放开,运行后结果为:当程序执行到finally里面是,它发现在里面也有一个return语句,这时候内存中会重新产生一个路径覆盖原来的那个,所以打出30.抛出异常把异常抛出,方法调用中常见。怎么抛出呢?格式:在方法名称后面跟一个关键字:throws 异常类名异常的分类:A:Exception下非RuntimeException 编译时异常B:RuntimeException 运行时异常异常处理两种方式:A:try...catch...finallyB:throws 请问我们选择谁?如果能够处理,尽量选择A。否则选择B。运行时期异常和编译时期异常的区别?A:运行时期异常是不需要try...catch或者throws的。B:编译时期异常编译时期异常是需要进行处理的。自定义异常 概述:java虽然已经考虑到了很多种异常情况,但是,有些需求java程序是考虑不到的。比如说:要求学生的年龄不能为负数;那么,针对这种情况,我们就要编写自定义异常类进行处理。如何编写一个自定义异常类呢?就是自定义一个类,去继承Exception或者RuntimeException。开发中:一般继承自RuntimeException。两道面试题:(1)Exception和RuntimeException的区别?A:Exception 编译时期异常,必须处理的。如果在方法上,throws了该类型的异常,将来调用者必须处理。如果在方法内部,throw了该类型的异常,必须在方法上throws该异常。B:RuntimeException 运行时期异常,是不需要处理的。要改代码的。如果在方法上,throws了该类型的异常,不需要处理。如果在方法内部,throw了该类型的异常,方法上可以throws该异常,也可以不throws该异常。(2)throw和throws的用法和区别? A:throw 用法:用在方法内部,后面跟的是异常对象名称。 区别:用throw抛出了编译时期异常,方法上面必须用throws抛出。 用throw抛出了运行时期异常,方法上面可以不用throws抛出。B:throws用法:用在方法声明上,后面跟的是异常类名。区别:用throws在方法上声明了异常,内部可以没有throw简单总结为两句话: throw在方法内部运行 抛出的是一个异常的对象 只能抛出1个throws在方法的声明处 抛出的是一个异常的类 可以多个 到这儿,异常的所有问题都总结完啦~~~ 有写的不对的地方,欢迎大家给我指正! 谢谢!!!------<ahref="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: