一 异常 - finally
1.示例代码
首先看下面这段代码,通过这段代码引入finally的概念:
class FuShuException extends Exception {
FuShuException(String msg) {
super(msg);
}
}
class Demo {
int div(int a, int b) throws FuShuException {
if (b < 0) {
throw new FuShuException("除数为负数。");
}
return a / b;
}
}
public class ExceptionDemo5 {
public static void main(String[] args) {
Demo d = new Demo();
try {
int x = d.div(4, -1);
System.out.println("x=" + x);
} catch (FuShuException e) {
System.out.println(e.toString());
//return; 注意这里,如果加了return;那么over不会被输出
} finally {
System.out.println("finally");// finally中存放的是一定会被执行的代码
}
System.out.println("over");
}
}
/*
* 输出:
* P1.FuShuException: 除数为负数。
* finally
* over
*/
注意catch语句块中的return; 它可以证明finally语句块中的语句一定会被执行。
2.finally语句的作用
那么,finally语句有什么用呢?
假设现在有个数据库,客户机连接数据库,
因为数据库的连接数是有限的(数据库也是主机),会自动断开连接,
无论是否取到数据,断开操作都是要执行的。这种断开操作、关闭资源的情况就需要用到finally语句了。
public void method(){ //用于操作数据库的方法
连接数据库;
数据操作//出问题,异常处理,抛SQL异常
关闭数据库 //“关闭数据库”动作,无论数据操作是否成功,一定要关闭资源
}
因此需要用到 try ……catch ……finally 的语句格式。
finally代码块:定义一定执行的代码,通常用于关闭资源。
3.举例说明
现在的模块化开发,会将各个功能分层,
就像一个超市,有 进货 - 仓库管理 - 销售 等等环节。
假如仓库漏水了,没理由销售去修补,
肯定是由仓库管理员处理,仓库管理员处理不了他再找搞工程的或者告诉老板。
因此,有些异常是要处理的(try...catch操作),有些是要抛的,
再举个例子:
可以通过Java程序调用虚拟机,想在硬盘上创建一个文件,java只要调用windows本身那个动作就可以了,
创建完要释放调用时的资源,要有关闭动作,此时也需要用到finally语句。
二 异常 - 处理语句其他格式
1.三种格式
一共有三种格式:
try可以单独和catch在一起 —— try...catch
也可以try……catch……finally在一起 —— try...catch...finally
try还可以单独跟finally在一起 —— try...finally
2.四个例子
例子1:
public class Demo {
public static void main(String[] args) {
try {
throw new Exception();
} catch (Exception e) {
}
}
}
上面的程序,编译能通过,因为问题在内部被解决了,外部不知道。
原则上只要问题被解决,问题可以不声明。
“有catch,就叫问题解决。”
例子2:
public class Demo {
public static void main(String[] args) {
try {
throw new Exception();
} catch (Exception e) {
throw e; // 编译不通过,因为抓住一个问题, 又抛了一个问题
}
}
}
上面的程序编译不通过,因为catch了一个问题,又throw了一个出来。
例子3:
public class Demo {
public static void main(String[] args) {
try {
throw new Exception();
} catch (Exception e) {
try {
throw e;
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
现在又可以了,因为问题被解决了。
例子4:
public class Demo {
public static void main(String[] args) {
try {
} finally {
// 关资源
}
}
}
“没有catch就没有处理。”
try……finally可以在一起,finally用于关资源。
3.总结
如果问题在内部被解决,比如内部catch(捕获),则该方法不用声明异常。
catch是用于处理异常的。如果没有catch就代表异常没有被处理过,如果该异常是检测时异常,那么必须声明。
三 异常 - 覆盖时的异常特点
异常声明在函数体内,而函数有覆盖特性,那么异常在子父类的覆盖中体现是怎样的呢?
异常在子父类覆盖中的体现:
1、子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。
2、如果父类方法抛出多个异常,那么子类在覆盖该方法时,子类只能抛出父类异常的子集。
3、如果父类或者接口的方法中,没有异常抛出,那么子类在覆盖方法时,也不能抛出异常。
4、如果子类方法发生了异常,就必须要进行try处理,绝对不能抛。
5、如果在子类的覆盖方法确实需要抛出非父类的异常或者该异常的子类,则必须在内部解决
关于第1点
class AException extends Exception {
}
class BException extends AException {
}
class CException extends Exception {
}
class Fu {
void show() throws AException {
}
}
class Zi extends Fu {
void show() throws AException { // 只能抛AException、BException,不能抛CException
}
}
只能抛AException、BException,不能抛CException,因为父类已经有问题了,
子类继承父类它的问题不能比父类更大,它的问题应该是比父类的范围小。
程序中继承关系如下:
|--AException
|--BException
|--CException
四 异常 - 练习
有一个圆形和长方形,都可以获取面积,
对于面积如果出现非法的数值,视为是获取面积出现问题。
问题通过异常通过异常来表示,现对这个程序进行基本设计。
class NoValueException extends RuntimeException {
NoValueException(String message) {
super(message);
}
}
interface Shape {
void getArea();
}
class Circle implements Shape {
private int radius;
public static final double PI = 3.14;
Circle(int radius) {
if (radius <= 0)
throw new RuntimeException("圆出先非法值");
this.radius = radius;
}
public void getArea() {
System.out.println(radius * radius);
}
}
class Rec implements Shape {
private int len, wid;
Rec(int len, int wid) {
if (len <= 0 || wid <= 0)
throw new NoValueException("正方形出先非法值");
this.len = len;
this.wid = wid;
}
public void getArea() {
System.out.println(len * wid);
}
}
class Demo {
public static void main(String[] args) {
// Rec r = new Rec(-3,4);
Circle r = new Circle(-8);
r.getArea();
System.out.println("over");
}
}
五 异常 - 总结
1、异常:是对问题的描述,将问题进行对象的封装。
2、异常体系:
Throwable
|--Error
|--Exception
|--RuntimeException
3、异常体系的特点:
- 异常体系中的所有类以及建立的对象都具备可抛性
- 也就是说可以被throw和throws关键字所操作
- 只有异常体系具备这个特点
4、throw和throws的用法
-
throw定义在函数内,用于抛出异常对象。
-
throws定义在函数上,用于抛出异常类,可以抛出多个用逗号隔开
5、当函数内中有throw抛出异常对象,并未进行try处理。必须要在函数上声明,否则编译失败。
注意:RuntimeException除外,也就是说,函数内如果抛出的RuntimeException异常,函数上可以不用声明
6、如果函数声明了异常,调用者需要进行处理,处理方法可以throws 也可以 try。
7、异常有两种
(1) 编译时异常
该异常在编译时,没有处理(没有抛出也没有try),编译失败。 → 该异常被标识,代表可以被处理。
(2) 运行时异常(编译时不检测)
-
在编译时,不需要处理,编译器不检查
-
该异常的发生,建议不处理,让程序停止,需要对代码进行修正
8、异常处理语句
(1)格式
try{
需要要被检测的代码
}catch{
处理异常的代码
}finally{
一定会执行的代码
}
(2) 组合
- try...catch
- try...finally
- try...catch...finally
(3) 注意
- finally中定义的通常是 关闭资源代码,因为资源必须释放
- finally只有一种情况不会执行,当执行到 System.exit(0); → System.exit(0); 系统退出,jvm结束
9、自定义异常(定义类继承Exception或者RuntimeException)
(1) 为了让该自定义类具备可抛性
(2) 让该类具备操作异常的共性方法
(3) 当要自定义异常的信息时,可以使用父类已经定义好的功能,异常信息传递给父类的构造函数。
classMyException extends Exception{
MyException(String message){
super(message);
}
}
(4) 自定义异常:按照Java面向对象思想,将程序中出现的特有问题进行封装。
10、异常的好处
- 将问题进行封装。
- 将正常流程代码和问题处理代码相分离,方便于阅读。
11、异常的处理原则
(1) 处理方式有两种:try 或者 throws
(2) 调用到抛出异常的功能时,抛出几个,就处理几个,一个try对应多个catch
(3) 多个catch,父类的catch放到最下面
(4) catch内,需要定义针对性的处理方式,不要简单的定义 printStackTrace ,输出语句,也不要不写
(5) 当捕获到的异常,本功能处理不了时,可以继续在catch中抛出
try{
throw new AException();
}catch(AException e){
throw e;
}
12、如果该异常处理不了,但并不属于该功能出现的异常,可以将异常转换后,再抛出和该功能相关的异常
或者异常可以处理,但需要将异常产生后和本功能相关的提供出去,调用者知道,并处理。
也可以将捕获的异常处理后,转换为新的异常
try{
throw new Aexceptihon();
}catch(Aexceptihon e){
//对Aexceptihon进行处理
throw new BException();
}
13、异常的注意事项
- 在子父类覆盖时,子类抛出的异常必须是父类的异常的子类或者子集
- 在子父类覆盖时,如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛出
参阅:
老师用电脑上课.java
图形面积.java
六 练习
省略,直接看视频比较好。
七 包(package)
Java中的包类似于项目里的文件夹。
当我们需要将各个类分门别类的存放的时候,
或者程序总需要有不同功能的相同类名的类时,需要用到包(package)。
1. PPT内容
- 对类文件进行分类管理。
- 给类提供多层命名空间(名称空间)。
- 写在程序文件的第一行(全小写)。
- 类名的全称的是:包名.类名。
- 包也是一种封装形式。
2. package的作用
- 为避免多个类重名的情况,如果出现两个相同名字的类,可通过包将两者区分,从而避免冲突
- 对类文件进行分类管理,可以将相关的一些类放在同一个包中。
- 给类提供多层命名空间,如A包中的Demo.class文件即packageA.Demo.class
- 分类管理,命名空间
3. 规则
写在程序的第一行,因为要先声明好这个类在哪个包下,注意全部小写。
类名的全称: 包名.类名。有了包名后,类名发生了变化,运行时按照包名.类名执行。
同时,在相应位置建立文件夹,将类文件放入文件夹中,源文件可以不管。
4. 使用中可能出现的错误
(1)类名写错。一旦类文件进入包,类名的全名改为:包名.类名,包与类文件构成一个整体。
代码要变现出来,运行时也要表现出来。
(2)包不在当前目录下。需要设置classpath,告诉虚拟机去哪里找包。
(3)类的权限不够大。有了包,范围变大后,涉及到权限问题。
一个包中的类要被其他包中的类访问,必须要有足够大的权限。外部类的权限修饰符只有2个:public和默认。
(4)函数的权限不够大。类公有后,被访问的成员也要公有,才可以被访问。
函数的权限有3:public、private和默认。类和函数都必须要公有。
包也是一种封装,有的类可以对外提供,有的只供内部使用。
所以,不能说封装只是私有,私有只是其中一种。只要没有public就算封装。
5. 示例代码
package pack;
public class PackageDemo {
public static void main(String[] args) {
System.out.println("Hello,Package!");
}
}
// javac -d . PackageDemo.java
// java pack.PackageDemo
// 指定其它目录:javac -d c:\myclass PackageDemo.java
// set classpath=c:\myclass 后再运行
编译时,设定路径将类文件放入指定的文件夹内,
例如,javac –d .PackageDemo.java,编译时将Package.class文件放入当前目录下的pack文件夹内;
系统自动生成pack文件夹,也可以将其指定在其他文件,例如:javac–d d:\myclass PackageDemo.java。
如果想设定classpath更快的找到包,只要设定路径为包的父目录即可,因为类文件和包是一个整体。例如:set classpath=c:\myclass
如果不写包,java会将当前文件夹作为默认包存在。
包的出现让java的源文件和类文件相分离,保护了源文件。最好将类文件单独存放,不要混在一起。
一般先写包,再写类,之前是把当前目录设为默认包了。
八 包与包之间访问
不同包中的类,要如何访问呢?
规则:
1、要访问其他包中的类,需要定义类名的全名:包名.类名
2、如果包不再当前目录下,需要设置classpath,告知虚拟机包的执行路径
3、有了包,范围变大,一个包中的类要被访问,必须有足够大的权限。
4、包与包间进行访问,被访问的包中的类以及类中的成员,需要public修饰。
5、不同包中的子类还可直接访问父类中被protected权限修饰的成员,protected是为其他包中的子类提供的一种权限。
包与包间可使用的权限有两种:public和protected。
6、其中protected只用于覆盖。
总结:
- 包与包直接进行访问,被访问包中的类及类中的成员,需要public修饰。
- 不同包中的子类,还可以直接访问父类中被protected权限修饰的成员。
- 包与包之间可以使用的权限有两种:public、protected。
四种权限的示意图:
“一个.java文件中不允许存在两个及两个以上的共有类public或者接口。”
“老师说手机给大家用,然后老师自己不见了,那手机还怎么用?”
“包也是一种封装形式,包、类、私有也是。”
九 导入import
1.为简化类名的书写,使用“import”关键字导入包
例如:import packageA.packageB.packageC.*;
意思是将包packageA下的包packageB下的包packageC下的所有类导入进来。
如果packageB下还有类需要导入,则还需import packageA.packageB.*;
2.import导入的是 包中的类,而通配符*导入的是 包中所有的类。
3.一个程序文件中只能有一条package语句,但可以有多条import语句。
4.建议不要写通配符*,需要用到包中的哪个类,就导入哪个类以便节省资源。
例如:写import mypack.Demo;而不写importmypack.*;
注意事项:
- 两个包中有相同类名文件,当再统一类中创建对象时,需要加上包名.类名创建。
- 建议定义包名不要重复,可以使用URL来定义,因为URL是唯一的。如:www.ABC.com---->package com.ABC.Demo
十 jar包
1. PPT内容
- Java的压缩包
- 方便项目的携带。
- 方便于使用,只要在classpath设置jar路径即可。
- 数据库驱动,SSH框架等都是以jar包体现的。
2. 一些常用的jar包
- java.util :utility工具包,包含一些使用工具类,如定义系统特性、使用与日期日历相关的函数等的类
- java.lang :language核心语言包;如String、Math、Integer、System、Thread,提供常用的功能。特殊之处是不需要导入,是作为默认导入的包。
- java.net :有关网络操作的包。
- java.io :输入输出流的包。
- java.sql :数据库操作包。
3. 如何操作jar包
jar包是Java特有的压缩文档,编译时通过jar.exe工具进行操作。
- 创建jar包:jar-cvf mypack.jar packageA
- 查看jar包:jar -tvf mypack.jar[>定向文件]
- 解压缩:jar -xvf mypack.jar
- 自定义jar包的清单文件:jar –cvfm mypack.jar mf.txt packa packb
补充:
- jar包和rar压缩包的区别:将类封装进jar包后仍然可以运行。但无法再更改、编译了,只能运行。
- jar包使用很方便,只要在classpath中设置好所用包的路径即可,方便项目的携带。网络上也有提供各种类供试用的jar包资源。
dos中命令使用:
-cfv:创建jar包并列出内部情况
-tvf:列出jar包的详细情况
c:\> dir>c:\1.txt,将c盘的目录列表存放在1.txt文件中。数据重定项,即让数据在文件中显示。
jar–tf rt.jar>c:\2.txt将这个包内容存在文件内。rt.jar是java的类库。
将java中的一些工具压缩成exe包,例如javac,内部都是类文件,主程序是tools.jar中的一个类文件。D:\jdk1.6.0_10\lib中的tools.jar,
编译所属的类都在此包中。java本身也是用类写成的,需要一个运行环境才能执行。
src.zip是java所有类的源文件。