Java入门学习笔记二——郝斌
1、抽象类
- 抽象类的由来
利用抽象类是为了更好的对类加以分类,就如同人类不但给各种具体植物取了名字还发明了“植物”这个抽象的词对所有具体植物进行归类一样 - Java用来模拟现实世界,所以也存在抽象类
- 抽象类通常用来作为一个类族的最顶层的父类,用最底层的类表示现实中的具体事物,用最顶层的类表示该类族所有事物的共性。
抽象方法
- 在定义Java方法时可以只给出方法头,而不给出方法内部实现代码,这样的方法称为抽象方法
- 凡是没有方法体的方法必须使用关键abstract修饰为抽象方法
- 凡是含有抽象方法的类都必须声明为抽象类
抽象类
- 用abstract关键字来修饰一个类时,该类叫做抽象类
- 包含抽象方法的类必须声明为抽象类
- 但是一个抽象类中却可以不包含任何抽象方法,尽管比较少见
- 抽象类不一定有抽象方法
- 有抽象方法的一定是抽象类
// 有抽象方法的类一定是抽象类
abstract class A
{
public void f(); //没有方法体的方法叫做抽象方法,抽象方法要求末尾必须得加分号,前面必须得加abstract
}
//抽象类不一定有抽象方法
abstract class B
{
public void g(){}
}
abstract class A //如果f方法没有方法体,则必须的在class前加 abstract 如果f方法含有方法体,
//则class前面可加也可不加abstract ,因为“一个抽象类中是可以不包含任何抽象方法,尽管比较少见”
{
abstract void f(); //如果f方法没有方法体,则f方法必须的声明为抽象方法,即必须的在前面加abstract
}
//class B extends A{} //error
//abstract class B extends A{} // ok
class B extends A // ok
{
public void f()
{
System.out.printf("BBBB\n");
}
}
class TestAbsPoly_1
{
public static void main(String[] args)
{
//A aa = new A(); // error 抽象类无法实例化
B bb = new B(); //OK
bb.f(); // OK
A aa; // OK 可以定义一个抽象类的引用,
aa = bb; //将子类对象的地址赋给抽象类的引用
aa.f(); //用抽象类的引用访问子类的方法,这就是多态
}
}
- 抽象类不一定有抽象方法
- 有抽象方法的一定是抽象类
- 不能new出抽象类对象,但可以定义一个抽象类的引用
- 我们可以把一个子类对象的地址赋给抽象类的引用,然后通过抽象类的引用调用子类从父类继承过来的方法,即抽象类也可以实现多态
假设A是抽象类,B是A的子类且完全实现了A的所有抽象方法,则A aa = new A();//error A aa = new B(); // OK
2、Final关键字
- final可以修饰:
- 整个类
- 类中若干个属性
- 类中的若干个方法
Final修饰整个类
- 表示该类不能被继承
- 如果认为一个类已经很完美且不需要定义子类来继承它时,可以使用它
- 格式:
public final class A {......}
public
和final
可以互换
//final修饰类表示该类不能被继承
//final类型修饰的属性必须在定义的同时初始化
//如果final类型修饰的属性没有在定义的同时初始化,则必须在该类中的所有构造函数中完成初始化
//不过这两种初始化只能存在一种,否则编译时会报错!因为final表示常量的意思,常变量当然不能被初始化两次了
class A //如果在class前面加final编译时程序就会报错
{
final int a = 10;//final定义的变量必须在定义的同时初始化
//如果这里只定义不初始化则我们就必须在所有的构造函数中完成对final变量的初始化
//不过这两种方式只能选择其中的一种
public A()
{
//a = 20;//只要前面对a进行了初始化,本语句就必须的被注释掉,否则编译时会报错!
}
}
class B extends A
{
}
public class TestFinal
{
public static void main(String[] args)
{}
}
Final修饰类中的若干属性
- Final修饰类中的若干属性表示该属性必须被赋值并且只能被赋一次值(注意默认值不算真正的赋值)
- 初始化方式有两种:(只能选择其中的一种)
- 在定义成员变量的同时初始化
- 在类中所有的构造函数中初始化
- 注意:一个类的所有普通方法内部都不可以修改final修饰过的成员变量的值
//表示该方法可以被子类继承,但不可以被子类重写
class A
{
public void f() //如果在public前面加final,则编译时就会报错
{
System.out.println("AAAA\n");
}
}
class B extends A
{
public void f() //重写父类的f方法
{
System.out.println("BBBB\n");
}
}
public class TestFinal_1
{
public static void main(String[] args)
{}
}
3、接口(interface)
接口的定义
接口就是抽象方法和常量值的集合。从本质上讲,接口是一种特殊的抽象类
接口的格式
[public] interface interfaceName [extends SuperInterfaceList]
{
...... // 常量定义和方法定义
}
interface It
{
int i = 20;
public void f();
}
abstract class B
{
public void f(){}
}
class A
{
public static void main(String[] args){}
}
接口的语法知识
- 接口中定义的属性必须是
public static final
的,而接口中定义的方法则必须是public abstract
的,因此这些修饰符可以部分或全部省略 - 接口中定义的属性的值在实现类中不能被更改
- 一个类只能实现某个接口,不能继承某个接口
- 一个类可以实现多个接口,但一个类不能继承多个类
- 但接口可以继承接口
- 接口不但可以继承接口,而且可以继承多个接口,即接口允许多继承
- 如果一个类只实现了一个接口的部分方法,则该类必须的声明为抽象类
- 一个类可以在继承一个父类的同时实现一个或多个接口,但
extends
关键字必须在implements
之前 - 不可以new接口对象,但可以定义一个接口引用类型的变量,并将其指向实现接口的对象,达到多态的目的(和抽象类一样)
//接口中是不可以定义构造函数的
interface It1
{
public static final i = 20; // 接口中定义的属性必须是public static final的
public abstract void f(); //接口中定义的方法则必须是public abstract的,
}
interface It2
{
int i = 20; // 因此这些修饰符可以部分或全部省略,不能改为 int i;
void f();
}
interface It3 extends It1, It2 //接口可以继承接口,而且可以继承多个接口,即接口允许多继承
{
}
class A implements It2 //一个类只能实现某个接口,不能继承某个接口
//implements不能改为extends 因为类可以继承类,但类不能继承接口,逻辑意义不通, 类可以实现接口
{
public void f()
{
//i = 99; // error 接口中定义的属性的值在实现类中不能被更改
System.out.printf("i = %d\n", i);
}
}
class B
{
}
//一个类可以在继承一个父类的同时实现一个或多个接口,但extends关键字必须的在implements 之前
class C extends B implements It1, It2
{
}
public class TestInterface
{
public static void main(String[] args)
{
A aa = new A();
aa.f();
}
}
interface It1
{
int i = 10;
void f();
}
interface It2
{
}
//class A implements It1 //error 类A不是抽象的,并且未覆盖It1中的抽象方法f()
//{}
abstract class B implements It1 // OK 如果一个类只实现了一个接口的部分方法,则该类必须的声明为抽象类
{
}
class C implements It1
{
public void f() // OK 方法重写,前面必须加public
//类C中的方法f访问权限必须大于等于接口It1中的方法f权限,否则报错
{
System.out.printf("AAAA");
}
public void g()
{
}
}
class TestInterface_1
{
public static void main(String[] args)
{
}
}
class A
{
int i; //属性没有赋值,会默认赋值为0
public void show()
{
System.out.printf("show-> %d\n", i); //i是属性i,此时的i等价于this.i
}
public void f()
{
//局部变量定义后,默认赋垃圾值,未赋值(未初始化)时不能使用,否则报错
int i; // 这里的i和属性i没有冲突
//System.out.printf("f-> %d\n", i); //error 因为i是局部变量,Java要求局部变量在使用之前必须得初始化
}
public void g(int i) //i是形参 形参i也是局部变量
{
this.i = i;
System.out.printf("g-> %d\n", i);
}
}
public class E
{
public static void main(String[] args)
{
A aa = new A();
//aa.g(99);
aa.show();
}
}
interface It
{
void f();
}
class A implements It
{
public void f()
{
System.out.printf("AAAA\n");
}
public void g()
{
}
}
class D
{
public static void main(String[] args)
{
//int i;
//It tt = new It(); // error
//It tt = new A(); //OK
//tt.f(); //OK
It it;
it = new A(); //不可以new接口对象,但可以定义一个接口引用类型的变量,
//并将其指向实现接口的对象,达到多态的目的(和抽象类一样)
it.f();
}
}
//如果一个类只实现了一个接口的部分方法,则该类必须得声明为抽象类
interface It1
{
void f();
void g();
}
abstract class A implements It1 // 去掉了abstract就会报错
{
//public不能丢,也不能改为其他修饰符
//一个类要想实现某接口中的方法时,必须得在方法返回值前加上public
public void f()
{
System.out.printf("AAAA\n");
}
}
public class TestInter_1
{
public static void main(String[] args)
{
}
}
接口的作用
- 通过接口可以实现不相关类的相同行为
- 如:Java规定所有可以完成自我复制功能的类都必须得实现
java.lang.Colneable
接口,但该接口却是空的,该接口中没有任何内容,目的只是为了起个标志作用
- 如:Java规定所有可以完成自我复制功能的类都必须得实现
- 接口提供了不同对象进行协作的平台
- 如事件处理
- 接口可以实现多继承,从一定程序上弥补了类只能单继承的缺陷
- 接口是我们了解一个类功能的重要途径
- 如:Java整个容器框架就是以接口的方式建立起来的,实现不同接口的类完成的是不同的功能,接口使我们了解一个类功能的重要途径
接口与抽象类区别
- 接口中的方法不允许有方法体,但抽象类却允许
- Java类不允许多继承,接口却允许多继承
- 接口可以实现多继承,即一个接口可以有多个父类
- 但Java类只允许单继承,即一个类只能由一个父类
4、包 package
package的使用
package
语句必须得是第一条语句package zhangsan.lisi
表示:把该文件中所有的类放入zhangsan.lisi
这个包中,并且该文件中所有的类真正名字将是包名和类名的组合- 如:;类
TestPackage
的名字将变成zhangsan.lisi.TestPackage
,而不再是TestPackage
- 编译时建议使用
javac -d . TestPackage.java
,尽量不要使用javac TestPackage.java
,因为后者要自己手动建立包目录。
javac -d . TestPackage.java
,-d
表示自动生成包层,.
表示这个包层是在当前目录下建立 - 如果不在当前路径下运行程序,则必须保证class文件的最上层目录的父目录位于
classpath
下
//文件名“TestPackage.java”
package zhangsan.lisi; //1行
public class TestPackage{
public static void main(String[] args){
new A().print();
}
}
class A{
public void print(){
System.out.println("AAAA");
}
}
java zhangsan.lisi.TestPackage
解析
先检测当前目录下是否有zhangsan/lisi
这个包(包即文件夹),如果有,再检测该包下是否有zhangsan.lisi.TestPackage
这个类,如果没有,编译器将再去classpath
设置的路径中依次查找。如果都查找失败,则运行时出错。
同包不同类的相互访问
//同包不同类的相互访问
//A.java文件
class A
{
public void f()
{
System.out.println("AAAA");
}
}
//B.java文件
class B
{
public static void main(String[] args)
{
A aa = new A();
aa.f();
}
}
执行如下命令:
javac A.java B.java
java B
输出结果:AAAA
附注:因为类A和类B默认是在同一个无名的包中所以彼此可以相互访问,只要是非私有成员都可以被同包的另一个类访问
不同包类的相互访问
//不同包类的相互访问
//文件名A.java
package zhangsan.lisi;
public class A
{
public void ma()
{
System.out.printf("AAAA\n");
}
}
//文件名B.java
package com.ruide
public class B
{
public static void main(String[] args)
{
zhangsan.lisi.A aa = new zhangsan.lisi.A();
aa.ma();
}
}
单独编译时必须得先编译A.java
,后编译B.java
,否则会出错
建议两个文件一起编译
javac -d . A.java B.java
javac -d . B.java A.java //两者都可以
使用不同包中类的第一种方式:
package com.ruide;
public class B
{
public static void main(String[] args)
{
zhangsan.lisi.A aa = new zhangsan.lisi.A(); //使用一个类的全名
aa.ma();
}
}
使用不同包中类的第二种方式:
package com.ruide;
import zhangsan.lisi.*;
public class B
{
public static void main(String[] args)
{
A aa = new A(); //使用import语句导入一个包中所有的类
aa.ma();
}
}
使用不同包中类的第三种方式:
package com.ruide;
import zhangsan.lisi.A;
public class B
{
public static void main(String[] args)
{
A aa = new A(); //使用import语句导入一个包中特定的类
aa.ma();
}
}
//注意:导入父包的类并不会自动导入子包的类
//如:import zhangsan.*; 只会导入zhangsan这个包下的所有类,并不会导入zhangsan子包lisi这个包中的类
//考虑:import java.awt.*; 和 import java.awt.event.*; 的区别
归档工具jar
- Java归档工具是
JDK
中提供的一种多用途的存档及压缩工具,可以将多个文件或目录合并压缩为单个的Java归档文件 - jar文件的主要作用:
- 发布和使用类库
- 便于资源的组合和管理
Jar使用举例
- 格式:
jar -cvf 要生成的包名.jar *
- 举例:
jar -cvf c.jar *
功能:把当前路径下所有的文件即文件夹下所有的内容打包成c.jar
jar -tf c.jar
功能:在DOS下显示c.jar
这个包解压后的文件内容jar -xf d:\1\ c.jar
功能:把d:\1\ c.jar
这个文件中的内容解压到当前目录下
如何使用jar包中的类
- 假设现在有一个
T.jar
包,要想在任何目录下都可以访问T.jar
包中的类,则设置classpath
时,必须把包名T.jar
也设置进去,因为T.jar
也相当于一个目录 - 如在
d:\share\java
下有一个T.jar
,则classpath
必须设置为d:\share\java\T.jar
,不能设置为d:\share\java
,也不能设置为d:\share\java\T
,否则在非当前目录下是无法访问T.jar
包中的类的
不同访问修饰符
不同情形下\访问说明符 | public | protected | default | private |
---|---|---|---|---|
同包同类 | √ | √ | √ | √ |
访问同包不同类 | √ | √ | √ | |
同包不同类继承 | √ | √ | √ | |
不同包继承 | √ | √ | ||
访问不同包无任何关系的类 | √ |
重点
- 在同一个包中只有私有的不能被另一个类访问,也只有私有的不能被继承
- 在不同包没有任何关系的两个类,只有public类的public成员才可以被另一个包中的类访问
- 在不同包中有继承关系的两个类,只有public类的public成员和public类的protected成员可以被另一个包中的子类在内部使用,但是在子类的外部,通过子类对象名只能访问父类的public成员
package test.pac;
public class A{
//可以把protected改为public,但却不能改为private,也不能在void前面什么都不写
protected void f()
{
System.out.printf("AAAA\n");
}
public static void main(String[] args)
{
A aa = new A();
aa.f();
}
}
package zhangsan.lisi;
import test.pac.*;
class B extends A{
public void g(){
f(); //OK 在子类的内部使用父类的保护方法
System.out.printf("GGGG\n");
}
}
class TestB{
public static void main(String[] args)
{
B bb = new B();
bb.g();
//bb.f(); //error
}
}
上述程序证明了:在不同包中有继承关系的两个类,只有public类的public成员和public类的protected成员可以被另一个包中的子类在内部使用,但是在子类的外部,通过子类对象名只能访问父类的public成员
package com.ruide;
public class A //public既不能去掉,也不能改为protected,也不能改为provate
{
public void f()
{
System.out.printf("AAAA\n");
}
}
package zhangsan.lisi;
import com.ruide.*;
class B
{
public void g()
{
A aa = new A(); //只有com.ruide.A是public时,才可以定义com.ruide.A对象
aa.f(); //只有com.ruide.A是public并且f方法是public时本语句才会正确
}
}
class M
{
public static void main(String[] args)
{
}
}
上述程序证明了:如果一个类A是public,但该类的方法成员和域成员是非public,则我们仍然可以在其他包中的类中定义类A的对象aa,但却无法通过类对象aa调用aa中的非public方法成员和非public域成员
5、异常
为什么需要异常
示例1:编程实现把键盘输入的数字赋给整型变量
import java.util.*;
public class TestExcept_1
{
public static void main(String[] args)
{
int i;
Scanner sc = new Scanner(System.in); // System.in表示键盘
try
{
i = sc.nextInt(); //如果输入的不是合法数字,没有异常处理的前提下,程序会异常终止
//本程序出现的问题是无法通过逻辑判断来解决的,Java提供的异常处理机制可以很好的解决这个问题
System.out.printf("i = %d\n", i);
}
catch (Exception e)
{
System.out.printf("输入数据不合法,程序被终止!\n");
}
}
}
class A
{
int divide(int a, int b)
{
return a/b;
}
public void f()
{
g();
}
public void g()
{
divide(6, 0);
}
}
public class TestExcep_4
{
public static void main(String[] args)
{
try
{
new A().f();
}
catch (Exception e)
{
e.printStackTrace(); // 不仅输出错误,而且输出错误路径
}
}
}
异常的处理机制
异常的定义
异常(Exception)是程序运行过程中发生的事件,该事件可以中断程序指令的正常执行流程。
异常的处理机制(重点)
- 当Java程序运行时出现问题时,系统会自动检测到该错误,并立即生成一个与该错误对应的异常对象
- 然后把该异常对象提交给Java虚拟机
- Java虚拟机会自动寻找相应的处理代码来处理这个异常,如果没有找到,则程序终止
- 程序员可以自己编写代码来捕捉可能出现的异常,并编写代码来处理相应的异常
import java.io.*;
class A
{
public void f() throws IOException
{
throw new IOException(); //throw 抛出异常
}
public void g()
{
throw new ArithmeticException();
}
}
public class TestExcep_1
{
public static void main(String[] args) //throws IOException
{
A aa = new A();
try
{
aa.f();
}
catch(IOException e)
{
}
}
}
常见的一些异常
- 常见异常之空指针异常
class Person
{
public int age;
}
public class TestNullPointerException
{
public static void main(String[] args)
{
Person p = null;
System.out.println(p.age); //运行时异常
}
}
运行结果是:
2. 常见异常之下标越界异常
public class TestIndexOutOf
{
public static void main(String[] args)
{
String friends[] = {"Lisa", "Bily", "Kessy"};
for (int i=0;i<5;i++)
{
System.out.println(friends[i]);
}
System.out.println("\nthis is the end");
}
}
运行结果是:
3. 常见异常之算术异常
class A
{
int divide(int a, int b)
{
return a/b;
}
}
public class TestArithExcep
{
public static void main(String[] args)
{
A aa = new A();
int i = aa.divide(3, 0);
System.out.println(i);
}
}
运行结果是:
异常的分类
Error
是系统错误,程序员无法处理这些异常Exception
是程序员可以捕获并处理的异常RuntimeException
的子类异常 是可以处理也可以不处理的异常- 凡是继承自
Exception
但又不是RuntimeException
子类的异常我们都必须得捕捉并进行处理
Error
:由Java虚拟机生成并抛出,包括动态链接失败、虚拟机错误等,Java程序无法对此错误进行处理Runtime Exception
:Java虚拟机在运行时生成的异常,如被0除等系统错误、数组下标超范围等,其产生比较频繁,处理麻烦,对程序可读性和运行效率影响太大。 因此由系统检测,用户可不做处理,系统将它们交给缺省的异常处理处理(当然,必要时,用户可对其处理)Exception
:一般程序中可预知的问题,其产生的异常可能会带来意想不到的结果,因此**Java编译器要求Java程序必须捕获或声明所有的非运行时异常。
异常处理步骤:
try
{
可能出现异常的代码块
}
catch(ExceptionName1 e)
{
当产生ExceptionName1 异常时的处理措施
}
catch(ExceptionName2 e)
{
当产生ExceptionName2 异常时的处理措施
}
......
finally
{
无论是否捕捉到异常都必须处理的代码
}
捕捉处理异常注意问题
Finally的作用
- 无论try所指定的程序块中是否抛出异常,也无论catch语句的异常类型是否与所抛弃的异常的类型一致,finally中的代码一定会得到执行
- finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分以前,能够对程序的状态作统一的管理
- 通常在finally语句中可以进行资源的清除工作,如关闭打开的文件、删除临时文件等
throw
throw
用来抛出异常- 格式:
throw new 异常名(参数);
- 假设f方法抛出了A异常,则f方法有两种方式来处理A异常
throws A
谁调用f方法,谁处理A异常,f方法本身不处理A异常try{...} catch(){...}
f方法本身自己来处理A异常
- 要抛出的异常 必须得是
Throwable
的子类
要抛出的异常 必须得是Throwable
的子类 示例
//去掉了extends Throwable 程序就会报错
class A extends Throwable
{
}
class M
{
public void f() throws A
{
throw new A(); //要抛出的异常 必须得是Throwable的子类
}
}
public class TestExcep_3
{
public static void main(String[] args)
{
}
}
throws
使用方法
void f() throws A
{
......
......
}
throws A
表示调用f方法时f方法可能会抛出A类异常,建议您调用f方法时最好对f方法可能抛出的A类异常进行捕捉throws A
不表示f
方法一定会抛出A
类异常
throws A
f
方法也可以不抛出A
类异常throws A
不表示调用f
方法时,必须得对A
类异常进行捕捉- 假设
A
是RuntimeException
子类异常 - 由于
RuntimeException
的子类异常可以处理也可以不处理,所以编译器允许你调用f
方法时,对f
方法抛出的RuntimeException
子类异常不进行处理
- 假设
- 强烈建议你:
- 对
throws
出的所有异常进行处理 - 如果一个方法内部已经对
A
异常进行了处理,则就不要再throws A
- 对
//本程序证明了:一个f方法throws A f方法可以不抛出A异常,调用f方法的方法也可以不处理A类异常
class ER extends RuntimeException
{
}
class A
{
public void f() throws ER
{
System.out.println("AAAA");
}
}
class M
{
public static void main(String[] args)
{
A aa = new A();
aa.f(); //输出结果:AAAA
}
}
注意问题
- 所有的
catch
只能有一个被执行 - 有可能所有的
catch
都没有执行 - **先
catch
子类异常再catch
父类异常- 如果先
catch
父类异常再catch
子类异常,则编译时会报错
- 如果先
catch
与catch
之间是不能有其他代码的- 重写方法抛出异常的范围不能大于被重写方法排除的异常范围
//子类覆盖了基类方法时,子类方法抛出异常的范围不能大于基类方法抛出的异常范围
//子类方法可以不抛出异常,也可以只抛出基类方法的部分异常,但不可以抛出基类方法以外的异常
//自定义异常A
class A extends Exception
{
}
//自定义异常B
class B extends Exception
{
}
//自定义异常C
class C extends Exception
{
}
class M
{
void f() throws A, B{
}
}
class N extends M
{
void f() throws A, B //可以throws A或B,也可以throws A,B 也可以不throws,但不可以throws C
//即“子类覆盖了基类方法时,子类方法抛出异常的范围不能大于基类方法抛出的异常范围”
{
}
}
class Test
{
public static void main(String[] args)
{
M m = new M();
N n = new N();
System.out.println("1111");
}
}
//先catch子类异常再catch父类异常
//如果先catch父类异常再catch子类异常,则编译时会报错
class A extends Exception
{
}
class B extends A
{
}
class C extends B
{
}
class M
{
public void compare(int i, int j) throws A, B
{
if (i > j)
throw new A();
else
throw new B();
}
}
public class TestTryCatch
{
public static void main(String[] args)
{
M mm = new M();
try
{
mm.compare(-4, 1);
}
catch (B bb) //子类异常
{
System.out.println("左边不能小于右边");
}
catch (A aa) //父类异常
{
System.out.println("左边不能大于右边");
}
}
}
异常的优缺点
异常的优点
没有错误处理的程序:
{
openTheFile;
determine its size;
allocate that much memory;
read-file;
closeTheFile;
}
以常规方法处理错误
openFiles;
if (theFilesOpen)
{
determine the length of the file;
if (gotTheFileLength)
{
allocate that much memory;
if (gotEnoughMemory)
{
read the file into memory;
if (readFailed) errorCode = -1;
else errorCode = -2;
}
else errorCode = -3;
}
else errorCode = -4;
}
else errorCode = -5;
以常规方法处理错误存在的问题:
- 观察前面的程序,大家会发现大部分精力花在出错处理上了
- 只把能够想到的错误考虑到,对以外的情况无法处理
- 程序可读性差,大量的错误处理代码混杂在程序中
- 出错返回信息量太少,无法更确切地了解错误状况或原因
异常的优点
用异常的形式来处理错误:
{
try
{
openTheFile;
determine its size;
allocate that much memory;
read-file;
closeTheFile;
}
catch(fileopenFailed) {dosomething;}
catch(sizeDetermineFailed) {dosomething;}
catch(memoryAllocateFailed) {dosomething;}
catch(readFailed) {dosomething;}
catch(fileCloseFailed) {dosomething;}
finally {dosomething;}
}
优点:
- 强制程序员考虑程序的安全性与健壮性
- 增强了程序员对程序的可控性
- 有利于代码的调试
- 把错误处理代码从常规代码中分离出来
注意: - 异常不一定能够使程序的逻辑更清晰
- 因为有时我们必须得编写代码捕捉异常,所以可能会导致程序的逻辑非常混乱
- 异常并不能解决所有的问题