面试题:
1、常见的异常都有哪些?举例说明,怎么处理异常
运行时异常:ArithmeticException 算术异常,ArrayIndexOutOfBoundsException数组角标越界,ClassCastException 类型转换异常
编译时异常(checked):IOException
不针对运行时异常编写try-catch-finally
2、throws、throw区别
throws声明异常是异常处理的方式, 捕获异常,声明在方法的声明处。
throw手动生成异常对象,抛出异常,声明在方法体内。可以同时使用,先抛出后捕获
3、final、finally、finalize三者的区别?
finalize不是关键字,是一个方法对象回收前会自动调用该方法
一、7.1 异常体系结构
Java程序在执行过程中所发生的异常事件可分为两类:
Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源
耗尽等严重情况。比如:StackOverflowError和OOM。一般不编写针对性
的代码进行处理。
Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使
用针对性的代码进行处理。例如:
空指针访问
试图读取不存在的文件
网络连接中断
数组角标越界
java.lang.Throwable 类
|-----java.lang.Error(子类):一般不编写针对性的代码进行处理。
|-----java.lang.Exception:可以进行异常的处理
-
|------编译时异常(checked)
-
|-----IOException |-----FileNotFoundException |-----ClassNotFoundException
|------运行时异常(unchecked,RuntimeException)
-
|-----NullPointerException 空指针异常
-
|-----ArrayIndexOutOfBoundsException数组角标越界
-
|-----ClassCastException 类型转换异常
-
|-----NumberFormatException 数值类型转换失败
-
|-----InputMismatchException 键入不匹配
-
|-----ArithmeticException 算术异常:除数分母为0
public class ExceptionTest{
//InputMismatchException
@Test
public void test5(){
Scanner scanner =new Scanner(System.in);
int score = sannner.nextInt();
System.out.printIn(score);//输入字母会报InputMismatchException异常
scanner.close();
}
//NumberFormatException
@Test
public void test4(){
String str ="123";
int num =Integer.parsInt(str);
//String str2 ="abc";
//int num =Integer.parsInt(str2); 字母不能强制转换为数值
}
//ClassCastException 类型转换异常
@Test
public void test3(){
Object obj =new Date();
String str =(String)obj;//报错数据类不能转换为string
}
//NullPointerException
@Test
public void test1(){
// int[] arr = null;//数组
// System.out.println(arr[3]);
//String str = "abc";
str = null;
System.out.println(str.charAt(0));//打印首字符
}
}
二、异常处理
抓抛模型
过程一:“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。
并将此对象抛出。
一旦抛出对象以后,其后的代码就不再执行。
关于异常对象的产生:
① 系统自动生成的异常对象
② 手动的生成一个异常对象,并抛出(throw)
过程二:“抓”:可以理解为异常的处理方式:
① try-catch-finally ② throws
try-catch-finally的使用
try{
//可能出现异常的代码
}catch(异常类型1 变量名1){
//处理异常的方式1
}catch(异常类型2 变量名2){
//处理异常的方式2
}catch(异常类型3 变量名3){
//处理异常的方式3
}
…
finally{
//一定会执行的代码
}
- 说明:
- finally内容是可选的。
- 使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配。无异常跳过catch执行finally
- 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的
try-catch结构(在没有写finally的情况)。继续执行其后的代码 - catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错 - 常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()
- 在try结构中声明的变量,再出了try结构以后,就不能再被调用
- try-catch-finally结构可以嵌套
体会1:使用try-catch-finally处理编译时异常,是得程序在编译时不报错,但是运行时仍可能报错。
体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。
针对于编译时异常,我们说一定要考虑异常的处理。
public class ExceptionTest1 {
@Test
public void test2(){
try{
File file = new File("hello.txt");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
System.out.print((char)data);
data = fis.read();
}
fis.close();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){//FileNotFoundException是其子类
e.printStackTrace();
}
}
@Test
public void test1(){
String str = "123";
str = "abc";
int num = 0;
try{
num = Integer.parseInt(str);
System.out.println("hello-----1");
}catch(NumberFormatException e){
// System.out.println("出现数值转换异常了,不要着急....");
//String getMessage():
// System.out.println(e.getMessage());
//printStackTrace():
e.printStackTrace();
}catch(NullPointerException e){
System.out.println("出现空指针异常了,不要着急....");
}catch(Exception e){
System.out.println("出现异常了,不要着急....");
}
System.out.println(num);
System.out.println("hello-----2");
}
}
public class Finally{
}
try-catch-finally中finally的使用:
- 1.finally是可选的
- 2.finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中有return语句,catch中有
- return语句等情况。
- 3.像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。
快捷操作:选中try的内容,右键surround with,try/catch block
printStackTrace打印堆栈信息
public void test2(){
FileInputStream fis = null;//初始化为null
try {
File file = new File("hello1.txt");
fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
System.out.print((char)data);
data = fis.read();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
throws +异常类型
public class Expection{
public static void main(String args){
try{
method2();
}catch(IOException e){
e.printStackTrace();
}
}
public static void method2() throws IOException{
method1();
}
public static void method1()throws FileNotFoundException,IOException{
}
}
开发中如何选择使用try-catch-finally 还是使用throws?
- 1 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,子类重写的方法中有异常,必须使用try-catch-finally方式处理。
- 2 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws 的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。
三、7.5手动抛出异常
public void regist(int id) throws Exception {
if(id > 0){
this.id = id;
}else{
//手动抛出异常对象
throw new RuntimeException(“您输入的数据非法!”);
// throw new Exception(“您输入的数据非法!”);
//throw new String(“不能输入负数”); //错误的,不是异常类型
}
}
如何自定义异常类?
- 继承于现有的异常结构:RuntimeException(运行时异常,不用显示处理:下例中 public class MyException extends RuntimeException时改为public void regist(int id) ) 、Exception
- 提供全局常量:serialVersionUID
- 提供重载的构造器
4.通用结构
public class MyException extends Exception{
static final long serialVersionUID = -7034897193246939L;//静态变量随类定义,标识MyException
public MyException(){
}
public MyException(String msg){
super(msg);
}
}
package com.atguigu.java2;
class Stydent{
private int id;
public void regist(int id) throws Exception {//显示处理,throws Myexception也可
if(id > 0){
this.id = id;
}else{
//手动抛出异常对象
throw new MyException("不能输入负数");
}
}
}
练习3 判断输出结果
package com.java;
public class ReturnExceptionDemo {
static void methodA() {
try {
System.out.println("进入方法A");
throw new RuntimeException("制造异常");//没有输出
} finally {
System.out.println("用A方法的finally");
}
}
static void methodB() {
try {
System.out.println("进入方法B");
return;
} finally {
System.out.println("调用B方法的finally");
}
}
public static void main(String[] args) {
try {
methodA();
} catch (Exception e) {
System.out.println(e.getMessage());//输出手动抛出的异常
}
methodB();
}
}
输出
进入方法A
用A方法的finally
制造异常
进入方法B
调用B方法的finally
练习4
接收命令行的两个参数
main方法中 ’int i = Integer.parseInt(args[0]);’
’int j = Integer.parseInt(args[1]);’
public class EcmDef {
public static void main(String[] args) {
try{
int i = Integer.parseInt(args[0]);
int j = Integer.parseInt(args[1]);
int result = ecm(i,j);
System.out.println(result);
}catch(NumberFormatException e){
System.out.println("数据类型不一致");
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("缺少命令行参数");
}catch(ArithmeticException e){
System.out.println("除0");
}catch(EcDef e){ //自定义异常类
System.out.println(e.getMessage());
}
}
public static int ecm(int i,int j) throws EcDef{
if(i < 0 || j < 0){
throw new EcDef("分子或分母为负数了!");
}
return i / j;
}
}