一 Java异常
1.异常的由来
在OO中提供的异常处理机制是提供代码健壮的强有力的方式。使用异常机制它能够降低错误处理代码的复杂度,如果不使用异常,那么就必须检查特定的错误,并在程序中的许多地方去处理它,而如果使用异常,那就不必在方法调用处进行检查,因为异常机制将保证能够捕获这个错误,并且,只需在一个地方处理错误,即所谓的异常处理程序中。这种方式不仅节约代码,而且把“概述在正常执行过程中做什么事”的代码和“出了问题怎么办”的代码相分离。总之,与以前的错误处理方法相比,异常机制使代码的阅读、编写和调试工作更加井井有条。(摘自《Think in java 》)。总之问题也是现实生活中的一个具体的事物,也可以通过Java的类的形式来进行描述,封装成对象。
异常的好处:
将问题进行封装。
将正常流程的代码和问题处理代码分隔开来,方便阅读性。
2. 异常定义
异常就是阻止当前方法或作用域继续执行的问题,当在一个方法中发生错误时,这个方法创建一个对象,并且把她传递给运行时系统,这个对象叫做异常对象。它包含有关错误信息,创建一个错误对象并把它传递给运行时系统叫做抛出异常。
一个方法抛出异常后,运行时系统就会试着查找一些方法来处理它,这些处理异常的可能的方法的集合被整理在一个方法列表中,这些方法能够被发生错误的方法调用,这个方法列表叫做堆栈调用,运行时系统搜寻包含能够处理异常的代码块的方法,这个代码块叫异常处理器,找到相应的处理器时,把异常传递给它,处理器会考虑类型是否匹配。
3.异常体系
异常体系特点:异常体系的所有类以及建立的对象都具有可抛性。
Throwable异常超类分为Error和Exception。
Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止,我们除了尽力使程序安全退出外,在其他方面也无能为力了。
Exception是程序本身可以处理的异常,这种异常分两大类:非运行时异常(发生在编译阶段,又称checkException)和运行时异常(发生在程序运行过程中,又叫uncheckException)。
非运行时异常一般就是指一些没有遵守Java语言规范的代码,容易看的出来,并且容易解决的异常,
运行时异常是那些在程序运行过程中产生的异常,具有不确定性,如空指针异常等,造成空指针的原因很多,所以运行时异常具有不确定性,往往难以排查,还有就是程序中存在的逻辑错误,光从一段代码中看不出问题,需要纵观全局才能发现的错误,也会造成运行时异常,这就要求我们在写程序时多多注意,尽量处理去处理异常,当异常发生时,希望程序能朝理想的方面运行!
4.异常处理方式
(1)try catch
在网上看了这样一个搞笑的话:世界上最真情的相依,是你在try我在catch。无论你发神马脾气,我都默默承受,静静处理。
try{ 需要被检测的代码 }
catch(Exception e){ 处理异常的代码方式 }
final{ 一定会执行的语句 }
第一种格式:try....catch
第二种格式:try...catch...final
第三种格式:try...final
throw和throws的用法:
throw定义在函数内,用于抛出异常对象。
throws定义在函数上,用于抛出异常类,可抛出多个用逗号隔开。
注意事项:
a:final定义一定执行的代码块,通常用于关闭资源。
b:final中的语句一定会执行,除非catch中有System.exit(0)系统退出方法。
c:catch中有return语句,会检测后面有木有final语句,没有则结束,有则执行下final语句,后面的语句不执行。
d:声明异常时,建议声明更为具体的异常,这样处理更可以更具体。
方法上声明几个异常,就对应有几个catch块,不要定义多余的catch块,如果出现多个catch块出现继承关系时,父类异常的catch块放在最下面。
e:当函数内容有throw抛出异常对象,并未进行try处理,必须要在函数上声明,否则编译失败。
f:如果函数声明了异常,调用者需要处理,可以throws也可以try。
对捕获到的异常对象进行常见方法操作。
1、处理异常。对所发生的的异常进行一番处理,如修正错误、提醒。
2、重新抛出异常。既然你认为你没有能力处理该异常,那么你就尽情向上抛吧!!!
3、封装异常。对异常信息进行分类,然后进行封装处理。
4、不要捕获异常。
5、异常信息不明确。将异常信息所在的类、方法、何种异常都需要记录在日志文件中的。
注意: 其实 jvm默认的异常处理机制,就是调用 printstacktrace方法。打印异常的堆栈的跟踪信息.
(2)自定义异常
因为项目中会出现特有的问题,为这些问题并未被Java所描述并封装对象,所有对于这些特有的问题可以按照Java对问题封装的思想,将特有的问题进行自定义封装。1、定义一个类继承Throwable或其子类。
2、添加构造方法(当然也可以不用添加,使用默认构造方法)。
3、在某个方法类抛出该异常。
4、捕捉该异常。
因为父类中已经把异常信息的操作都完成了,所以子类在构造时,将异常信息传递给父类通过super语句,那么就可以通过getmessage方法获取自定义的异常信息。
class MyException extends Exception
{
public MyException(){
}
public MyException(String message){
super(message);
}
}
public class Test1{
public void method(int x)throws MyException{//抛出异常需要声明异常
if(x==0)
//如果等于0,则抛出异常。
throw new MyException("除数不能为零");
System.out.println(2/x);
}
public static void main(String[] args)throws MyException{
Test1 t=new Test1();
t.method(0);
}
(3)RuntimeException运行时异常
Exception中有一个特殊的子类异常runtimeException 运行时异常,如果在函数内部抛出该异常,函数上可以不用声明,编译一样通过。如果在函数上声明了异常,调用者可以不进行处理,编译一样通过。
自定义异常时,如果该异常的发生无法在继续运行程序,就让自定义异常继承RuntimeException。
5. 异常处理使用小知识点
(1)尽可能的减小try块。(2)保证所有资源都被正确释放。充分运用finally关键词。
(3)catch语句应当尽量指定具体的异常类型,而不应该指定涵盖范围太广的Exception类。 不要一个Exception试图处理所有可能出现的异常。
(4)既然捕获了异常,就要对它进行适当的处理。
(5)在异常处理模块中提供适量的错误原因信息,组织错误信息使其易于理解和阅读。
(6)不要在finally块中处理返回值
(7) 不要在构造函数中抛出异常
6.异常的处理原则
(1)处理方式俩种try或者throws。(2)调用到抛出异常的函数时,抛出几个处理几个。多个异常时,就会出现一个try对应多个catch。
(3)多个catch语句块时父类的catch放在最下面。
(4)catch中需要定义针对性的处理方式,不要不写。
(5)当捕获到的异常本功能处理不了时,可以继续throw抛出。 如果处理不了并且不属于该功能出现的异常可以将异常转换后,再抛出和该功能相关的异常。当异常可以处理,需要将异常产生的和本功能相关问题提供出去,让调用者处理。也可以将捕获到的异常转换成新的异常。
7.异常在父类覆盖中的体现
(1 )子类在覆盖父类时,如果父类的方法抛出了异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。
(2)如果父类的方法抛出多个异常,那么子类在覆盖方法时,只能抛出父类异常的子集,不能超过父类。
(3)如果父类或接口中的方法没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常,如果子类发生了其他异常,就必须要进行try处理,绝对不能抛出去。
8、常见异常
NullPointerException 空指针空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。
譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等
ClassNotFoundException 找不到类
找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
ClassCastException 类型转换
ArithmeticException 算数条件
算术条件异常。譬如:整数除零等。
ArrayIndexOutOfBoundsException 数组越界
数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
二 包
1. 概念
包说简单点就是文件夹,可以把包看作是管理类文件的文件夹,因为项目越大,文件和类越多。
包的好处:
1) 将功能相近的类放在同一个包中,可以方便查找与使用。
2) 由于在不同包中可以存在同名类,所以使用包在一定程度上可以避免命名冲突。
3) 在Java中,某次访问权限是以包为单位的。
4)给类提供多层命名空间
2 .创建包
创建包可以通过在类或接口的源文件中使用 package语句实现,package语句的语法格式如下:
package 包名;
包名:必选,用于指定包的名称,包的名称为合法的 Java标识符。当包中还有包时,可以使用“包1.包2.…….包n”进行指定,其中,包1为最外层的包,而包n则为最内层的包。
注意:
package 语句通常位于类或接口源文件的第一行。
写在程序的第一行。包名.类名。所有包名小写。
3. 导入包
为了简化类名的书写,使用关键字import。
例如,import java.lang.*;import java.*;
注意:
a:导入包时, *来替代导入包中的所有类。但是,建议不要使用通配符 * ,因为将不需要使用的类导入后,会占用内存空间。所有在编写程序时,要使用包中的哪些类,就导入哪些类。
b:导入的不同包中有相同类时,必须写类的全名以区分,否则将会报错。
c:import 导入的是本包中的类如果此包中有子包,不包含子包中的类。
建议建立包名不要重复,可以用URL来定义,因为URL是唯一的。
比如;www.baidu.com com.baidu.demo
3.包与包的关系
(1)包与包之间进行访问,被访问的包中的类以及类中的成员,需要被public修饰。
(2)不同包中的子类可以访问父类中被protected权限修饰的成员。
(3)包与包之间可以使用的权限有俩种:public和protected。
包中类的权限关系;
| public | protected | default | private |
同类 | OK | OK | OK | OK |
同包 | OK | OK | OK | NO |
不同包子类 | OK | OK | NO | NO |
不同包 | OK | NO | NO | NO |
注意:一个类中,只能有一个类是public的,被修饰后该类名字需要和文件名一样。
4.打包
当文件过多过大时,我们一般会用压缩工具来压缩成较小的来存放,Java中也可以用jar工具来压缩包。
打包的好处:
1、 可以将多个包进行压缩到为一个文件。文件小方便项目的携带。
2、 使用方便,不需要再使用命令打开,只要在classpath设置jar路径,即可以执行jar包中双击它,运行该java程序。
3、 数据库驱动,SSH框架等都是以jar包体现的。
创建jar包
jar -cvf Test.jar day01
day01为文件夹下的所有class文件都打包
查看jar包
jar -tvf day.jar
解压缩
jar -xvf day.jar