第一部分:异常体系
一、异常的定义及由来
1)定义:异常就是程序在运行时出现的不正常情况
2)异常由来
问题也是现实生活中的一类具体的事物,也可以通过Java类的形式进行描述,并封装成对象,就是异常。也就是Java对不正常情况进行描述后的对象体现。
二、异常体系
|---- Throwable
|---- Error
|---- Exception
|---- RuntimeException
异常分为两种:
1、严重的:Java通过Error类进行描述。Java一般不编写针对性代码进行处理。
2、对于不严重的:Java通过Exception类进行描述。可以使用针对性方式进行处理。
如:ArrayIndexOutOfBoundsException。
无论是Error还是Exception,都具有一些共性内容,将这些共性内容向上抽取,形成一个体系,抽取的父类就是Throwable。
第二部分:异常的处理
如果功能内部抛出了异常或函数上申明了异常(非RuntimeException及其子类),调用者必须要对申明的异常进行处理。处理方式有两种:
(a)在函数内部进行try catch 处理。
(b)在函数上申明,让调用者处理。
1、Java提供了特有的语句进行处理
格式一:
try
{
需要被检测的代码;
}catch(异常类 变量)
{
处理异常的代码;
}
格式二:
try
{
需要被检测的代码;
}catch(异常类 变量)
{
处理异常的代码;
}finally
{
一定会执行的语句;
}
格式三:
try
{
需要被检测的代码;
}catch(异常类 变量)
{
处理异常的代码;
}
... ...
finally
{
一定会执行的语句;
}
格式四:try
{
需要被检测的代码;
}finally
{
一定会执行的语句;(一般是关闭资源的动作)
}
使用上述代码块可以将正常流程代码与处理异常的代码分开,方便阅读。2、对捕获到的异常进行常见操作
String getMessage() 获取异常信息
String toString() 获取异常名称及异常信息
void printStackTrace() 打印跟踪信息,包括异常名称、异常信息、异常出现的位置
JVM默认的异常处理方式,就是在调用printStackTrace()方法,打印异常堆栈中的跟踪信息。
3、关键字throw与throws
throw:使用在函数内,用于抛出异常对象。
throws:使用在函数上,申明该功能内部有异常抛出,谁调用,谁处理,否则编译失败。(throws后面可以跟多个异常)
注意:
throw与throws单独存在时,下面不要定义语句,因为执行不到。
4、对多异常的处理
1)申明异常时,建议申明更为具体的异常。
2)对方申明几个异常,就对应几个catch块,不要定义过多的catch块。
3)在进行catch处理时,catch中一定要定义处理方式,不要只简单的打印异常信息。如果多个catch块中的异常出现继承关系,父类异常的catch块要放在最后面。
4)如果发生的异常并不属于该功能出现的异常,可以将异常转换(处理)后再抛出和功能相关的异常对象,让调用者进行处理。开发中一般会将异常信息存放在硬盘中,生成一个日志文件。
示例代码:
package demo; class Demo { int div(int a,int b)throws ArithmeticException//函数上申明异常 { if(b<0) throw new ArithmeticException();//函数内部抛出异常 return a/b; } } public class ExceptionDemo { public static void main(String[] args) { Demo d = new Demo(); try { System.out.println(d.div(4,0));//可能发生异常,需要进行检测 } catch (ArithmeticException e)//处理捕捉到的异常 { e.printStackTrace();//打印异常信息 } System.out.println("over"); } }
运行结果:
第三部分:自定义异常
因为项目中会出现特有的问题,而这些问题并未被Java描述并封装成对象,所以对于这些特有的问题可以按照Java的对问题封装的思想,将特有的问题,进行自定义的异常封装。
1、定义类继承Excepiton
异常体系有一个特点,因为异常类和异常对象都可以被抛出,他们都具备可抛性,这个可抛性是Throwable这个体系中的都有特点,只有这个体系中的类和对象才可以被throw和throws操作。
2、自定义异常信息
因为父类已经把异常信息的操作完成了,所以子类只要在构造时,将异常信息传递给父类,通过super语句,就可以通过getMessage()等方法获取自定义信息。
示例代码:
/* 需求:自定义异常,当被负数除时抛出异常 */ class FuShuException extends RuntimeException//定义FuShuExcepiton继承RuntimeException { FuShuException(String message) { super(message);//父类已经对异常信息进行了相应的处理,直接将信息传给父类就可以了 } } class Demo { int div(int a,int b) throws FuShuException//将异常抛给调用者 { if (b<0) { throw new FuShuException("出现除数为负数的异常!/ by FuShu");//抛出异常对象,并传递异常信息 } return a/b; } } class ExceptionDemo4 { public static void main(String[] args)//throws FuShuException 将异常抛给虚拟机 { Demo d = new Demo(); try { int x = d.div(4,-1); System.out.println(x); } catch (FuShuException f)//捕捉异常,并给出处理方式 { System.out.println(f.toString()); } System.out.println("over"); } }
运行结果:
第四部分:RuntimeException
异常分两种,编译时异常与运行时异常。
1、编译时异常:该类异常调用者必须进行处理(try或者抛),否则编译失败。
2、运行时异常
函数内部抛出了该异常对象,函数上可以不用申明,调用者不用进行处理,编译一样通过。
之所以不用让调用者处理,是因为当该异常发生时,需要让该程序停止。因为出现了无法继续运算的代码,希望程序停止,对代码进行修正。该异常就是RuntimeExcepton。
自定义异常时,如果该异常的发生无法继续运算,默认让自定义异常继承RuntimeException。
第五部分:子父类中异常的特点
第六部分:包1、子类覆盖父类时,如果父类方法抛出异常,那么子类覆盖方法,只能抛出父类异常或者父类异常的子类。
2、如果父类或接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。若子类方法发生异常, 就必须要进行try处理,不能向外抛出。
一、包的特点
1、对文件进行分类管理。
2、给类提供多层命名空间。
3、写在程序的第一行。
4、类的全名是:包名.类名。
5、包也是一种封装形式。
示例代码:
package com.itheima;//定义一个包 public class Test1 { public static void main(String[] args){ printString(); } public static void printString() { String str = "abc"; System.out.println(str); } }
编译时:到源文件所在路径按以下格式进行编译
javac -d c:\myclass Test1.java
表示编译Test1.java文件,并将生成的二进制(.class)文件存放到c:\myclass文件夹下,并在c:\myclass目录中自动生成了一个文件夹com,其中有itheima文件夹,且itheima文件夹中存放有Test.class文件。
当将c:\myclass替换成”.“时,表示生成的二进制文件存放到当前目录下。(Java的默认包就是当前目录)
运行时:
java com.itheima.Test1
运行时先将classpath设置到c:\myclass目录下,然后再运行二进制文件的全名:包名.类名。
二、包与包之间的访问
1、包与包中的成员在进行访问时,要注意以下几点:
1)类名要写全名:包名.类名。
2)将包的父目录设置到classpath中,告知JVM包的位置。
3)权限问题。类及需要被访问的成员前需要加public修饰。
4)Java给不同包中的子类提供了一个特有权限:protected,即A包中的子类可以访问B包中的父类中被protected修饰的成员。
5)一个源文件(.java文件)中不可以出现两个以上的公有类或接口,因为类公有后,类名必须和.java文件名一致。
2、各个权限在不同情况下的访问情况
三、关键字 import
包的出现方便了对.class文件的管理,但是在访问时需要些全名,较为麻烦,为了简化书写,使用关键字:import。如:
import com.itheima.Test1;
表示导入当前目录的com文件夹中的itheima文件夹中的Test1类。导入该类后,以后再需要使用该类中的成员时,就不需要些包的全名了,只写类名即可。
若Test1改为通配符“*”,则表示导入该包中的所有类,但不建议写通配符,需要哪个类就导入哪个类。
使用的注意事项:
1、导入不同包中的同名类,该类在使用时必须加包名。
2、定义包名时建议不要重复,可以使用URL来定义,因为URL是唯一的。