Java异常机制
Java异常机制
引入案例
public FileInputStream(String name) throw FileNotFoundException
上代码中,FileInputStream的构造函数将根据参数name构造一个FileInputStream,但是也有可能会抛出一个FileNotFoundException,当发生FileNotFoundExcepton时,运行时系统就会开始搜索异常处理器,以便知道如何处理FileNotFoundException。
受查异常
派生于Error类或RuntimeException类的异常被划分为非受查异常,其他异常为受查异常,对于非受查异常用户不需要抛出,对于受查异常,用于应当选择抛出。
Error类对应的异常如:{虚拟机内部错误,资源消耗殆尽},程序遇到这些错误时会直接终止运行,用户不应当抛出这类异常。
RuntimeException对应异常如:{NullPointerException,数组下标越界错误,除0错误},用户应当尽力避免这些错误,而不是抛出这些错误,抛出这些错误会造成程序冗长繁杂。
对于受查异常,如IOException,当一个方法抛出一个IOException时,一个重要的功能是提醒调用者应当注意这类异常。
## 抛出异常
在使用FileInputStream类的构造方法时,注意该方法的原型
public FileInputStream(File file)
throws FileNotFoundException
throws FileNotFoundExcepiton表示该方法可能会抛出一个FileNotFoundException,此时必须显式抛出或捕捉此异常,否则编译不通过,当选择抛出时,注意下代码不仅ReadFile方法要抛出FileNotFoundException,ReadFile方法的调用者main也要抛出FileNotFoundException异常。一个方法抛出异常意味着此方法内部并不处理这个异常,方法的设计者希望方法的调用者去处理这个异常。
class Main
{
public void readFile(String path) throws FileNotFoundException,IOException{
FileInputStream fis=new FileInputStream(path);
byte []buf=new byte[1024];
int len=-1;
while((len=fis.read(buf,0,buf.length))!=-1){
System.out.println(new String(buf));
}
fis.close();
}
public static void main(String [] args) throws FileNotFoundException,IOException{
new Main().readFile("a.txt");
}
}
关键字throw和throws
throws放在一个方法头中,表明该方法可能能够会抛出某某异常,throw常用于主动抛出一个异常,这个异常一般是自定义的异常,对于已经定义好的异常,如FileNotFoundException,这种异常有自己的“触发器”,当“触发器”触发时,该异常被自动抛出;但自定义的异常缺少“触发器”,需要手动的抛出,注意看自定义异常的小节。
捕获并处理异常
上代码中,异常一直被往上抛,交由JVM,这是不合适的,我们应当在适当的地方去捕捉并处理异常,如:
public void readFile(String path){
FileInputStream fis=null;
try{
fis=new FileInputStream(path);
}catch(FileNotFoundException e){
System.out.println("文件找不到!");
e.printStackTrace();
}
byte []buf=new byte[1024];
int len=-1;
try
{
while((len=fis.read(buf,0,buf.length))!=-1){
System.out.println(new String(buf,0,len));
}
}catch (IOException e)
{
e.printStackTrace();
}finally{
try{
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
这样的代码显得很有些冗长繁杂......
try-catch-finally执行顺序
程序先进入try语句块,依次执行,在未发生异常的情况下执行完毕后进入finally语句块,依次执行(不执行catch中的语句)。
try语句块中,当发生异常时立即进入catch语句,依次执行catch语句中代码,执行完毕后进入finally语句,依次执行。
带资源的try语句
下代码中,并没有关闭输入流fis,带资源的try语句不论在那种情况下都会确保文件流被关闭。
public void readFile(String path) {
byte[] buf = new byte[1024];
int len = -1;
try (FileInputStream fis = new FileInputStream(path)) {
while ((len = fis.read(buf, 0, buf.length)) != -1) {
System.out.println(new String(buf, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
自定义异常
public class Main {
public class MyFormatException extends Throwable{
public MyFormatException() {}
public MyFormatException(String message) {
super(message);
}
}
public boolean juede(char []bf) throws MyFormatException {
if(bf[0]!=1) {
throw new Main.MyFormatException("字符数组格式错误");
}
return true;
}
public static void main(String[] args) {
char []bf= {'0','1'};
boolean a=false;
try {
a=new Main().juede(bf);
}catch(MyFormatException e) {
e.printStackTrace();
}
System.out.println(a);
}
}
抛出异常的强制规则
1. 重写方法抛出异常抛出异常规则
重写方法只能抛出的异常必须被父类方法抛出的异常包含,当父类方法没有抛出异常时,重写方法不允许抛出异常,此时只能捕捉异常。
异常使用规范
1. 对于一些异常,使用检查而不捕捉
对比两种方式:
捕捉方式下:
public static void main(String[] args) {
Stack s=new Stack();
try {
s.pop();
}catch(EmptyStackException e) {
e.printStackTrace();
}
}
检查方式下:
public static void main(String[] args) {
Stack s=new Stack();
if(!s.empty()) {
s.pop();
}
}
检查上下的代码更简洁并且也更好!
2.
案例
下面的代码运行时是健壮的,设计良好的程序不容易因为一些偶然的原因而崩溃掉!
下面一块代码,没有意外的情况下,函数返回两数相除的结果,在发生意外时函数返回一个null值。
public String divided(int a,int b) {
String s=null;
try {
s=Integer.toString(a/b);
}catch(ArithmeticException e){
return null;
}
return s;
}
个人感受
- 昨天晚上和今天上午主要看完了Java 异常框架,大部分应当是理解了,有些更细节的东西需要在实际编码中去领会。
- 下午看Java GUI,嗯,这条线没有被拓开,就感觉看的脑壳疼,毕业设计题目是与Java GUI相关,因此这块是应当去认真学习的,现在的话感觉需要做两件事,一者是梳理常见api,然后多码练习手感,二者是去感受里面的事件处理机制,这是比较拗口的一件事情,一旦这二者基本完成,我就可以正式的开始毕设作品的编写了。
- 晚上写斐波那契数列时,比较了递归和循环的效率,从第一项计算到第40项,递归需要耗时844ms,而循环仅需2ms,这其中的差别是巨大的。
- 传统的跳转语句有四种return\continue\break\goto,goto我从未用过,这个语句被业内所业务,这是很自然的,但是又换句话说,这又是有些不恰当的,goto语句无条件的任意跳转难以控制,但是想来有的时候或许也会是一种不错的方案。去掉goto语句的换,return\continue\break,已经足以胜任所有的程序跳转功能,唯一不好的一点时在多层循环的时候难以使用,仅能通过标志变量去精确控制其跳转行为。java提供一个标记循环的新特性,用于解决多层循环跳转的麻烦问题,这很好,但是又让我有些郁闷,这些新特性是很好(在此处我并不只针对该特性),但是却会加大学习的成本和大脑在应用时的负担,C语言短小精炼,嗯,学习的到一定程度都会对C的基本所有特性都达到掌握,但是学习Java却总感觉被山压着,一打开API文档#手动郁闷,靠#这又是啥玩意,丢下这种包袱的好的做法是从思维上去学习这门语言,以及其他的语言。
建议
-
不应当控制屏幕
-
不应当强制收手机
评论留言