java == 出错_Java 通过异常处理错误(下)

7.java标准异常

Throwable这个java类用来表示任何可以作为异常被抛出的类.Throwable对象可以分成两种, 一种时error, 用来表示编译时和系统错误, 一般用户不需要关心, 需要关心得是另一种Exception, 表示可以被抛出的基本类型, 在java类库, 用户方法,以及运行时故障可能抛出Exception行异常, 所以java一般更关心Exception.

7.1 特例: RuntimeException

如果调用了null的对象, 就会抛出NullPointerException, 这不需要你亲自动手去抛出, 而是java会自动抛出, 而NullPointerException属于运行时异常, 是继承自RuntimeException, 运行时异常不需要亲自去动手捕获, java会自动帮你捕获;

public class NeverCaught{

static void f() {

throw new RuntimeException("From f()");

}

static void g() {

f();

}

public static void main(String[] args) {

g();

}

}

对于这种异常类型, 不需要异常说明, 其输出就被报告给了System.err

Exception in thread "main" java.lang.RuntimeException: From f()

at NeverCaught.f(NeverCaught.java:3)

at NeverCaught.g(NeverCaught.java:6)

at NeverCaught.main(NeverCaught.java:9)

[Finished in 1.0s with exit code 1]

记住只有RuntimeException及其子类是可以在代码中忽略的, 其他类型的异常处理有编译器强制执行.

8.使用finally进行处理

对于一些代码, 无论try块是否有异常抛出, 都能得到处理, 比如对文件操作, 执行完了总是应该把文件关闭掉, 这时候就可以在异常处理最后再加上finally字句

class ThreeException extends Exception{}

public class FinallyWorks {

static int count = 0;

public static void main(String[] args) {

while(true) {

try {

if (count++ == 0) {

throw new ThreeException();

}

System.out.println("No Exception");

} catch (ThreeException e) {

System.out.println("ThreeException");

} finally {

System.out.println("In finally clause");

if (count == 2) break;

}

}

}

}

ThreeException

In finally clause

No Exception

In finally clause

如果try中有return呢? 是否还是能总是被执行呢?

public class MultipleReturn {

public static void f(int i) {

System.out.println("Initialization that requires cleanup");

try {

System.out.println("point 1");

if (i == 1) return;

System.out.println("point 2");

if (i == 2) return;

System.out.println("point 3");

if (i == 3) return;

System.out.println("End");

return;

} finally {

System.out.println("Performing cleanup");

}

}

public static void main(String[] args) {

for (int i = 1; i <= 4; i++) {

f(i);

}

}

}

结果是肯定的当然是能的

Initialization that requires cleanup

point 1

Performing cleanup

Initialization that requires cleanup

point 1

point 2

Performing cleanup

Initialization that requires cleanup

point 1

point 2

point 3

Performing cleanup

Initialization that requires cleanup

point 1

point 2

point 3

End

Performing cleanup

遗憾: 异常丢失, 异常作为程序出错的标志, 应该不能被忽略, 然而还是有可能被轻易的忽略的, 用某些特殊的方式使用finally子句, 就会发生这种情况:

class VeryImportantException extends Exception {

public String toString() {

return "A very important exception!";

}

}

class HoHumException extends Exception {

public String toString() {

return "A trivial exception";

}

}

public class LostMessage {

void f() throws VeryImportantException{

throw new VeryImportantException();

}

void g() throws HoHumException {

throw new HoHumException();

}

public static void main(String[] args) {

try {

LostMessage lost = new LostMessage();

try {

lost.f();

} finally {

lost.g();

}

} catch (Exception e) {

System.out.println(e);

}

}

}

结果只输出了A trivial exception, VeryImportantException咋被吃掉了? 被finally子句中抛出HoHumException给取代了.

更加粗暴的一种异常丢失情形:

try {

throw new Exception();

} finally {

return;

}

9. 异常限制

当子类覆盖父类的方法时, 只能抛出基类方法异常说明中列出的异常

异常限制对构造器不起作用,派生类的构造器的异常说明必须不少于基类构造器的异常说明。且派生类构造器不能捕获基类构造器抛出的异常。

不抛出性。派生类方法可以不抛出任何异常,即使它是基类所定义的异常。

尽管在继承过程中,编译器对异常说明所强制要求,但是异常说明本身不是方法的一部分,方法是由方法的名字与参数的类型组成的。

异常限制与继承规则不同。某个方法的异常说明 不能变大,只能变小或者不变。

10 构造器

如果异常发生了, 所有东西总是能被正确的清理吗?

大多数情况下是可以的, 但是遇到构造器就会有各种问题, 比如在构造器中打开了一个文件,

进行异常捕获, 应该在finally中关闭文件吗? 万一如果文件都还没有打开就抛出异常, 那么关闭文件就没有意义了, 最安全方法就是嵌套使用try

import java.io.*;

class InputFile{

private BufferedReader in;

public InputFile(String fname) throws Exception {

try {

in = new BufferedReader(new FileReader(fname));

} catch(FileNotFoundException e) {

System.out.println("Could not open " + fname);

throw e;

} catch (Exception e) {

try {

in.close();

} catch (IOException e2) {

System.out.println("in.close() unsucessful");

}

throw e;

} finally {

}

}

public String getLine() {

String s;

try {

s = in.readLine();

} catch (IOException e) {

throw new RuntimeException("readLIne() failed");

}

return s;

}

public void dispose() {

try {

in.close();

System.out.println("dispose() successful");

} catch (IOException e2) {

throw new RuntimeException("in.close() failed");

}

}

}

public class Cleanup {

public static void main(String[] args) {

try {

InputFile in = new InputFile("Cleanup.java");

try {

String s;

while((s = in.getLine()) != null) {

// System.out.println(s);

}

} catch (Exception e) {

System.out.println("Caught Exception in main");

} finally {

in.dispose();

}

} catch (Exception e) {

System.out.println("InputFile construction failed");

}

}

}

11 异常匹配

抛出异常的时候, 异常处理系统会按照代码的书写顺序找出"最近"的处理程序, 找到匹配的处理程序后, 就认为异常将得到处理, 然后就不在继续查找.

查找的时候并不要求异常同处理程序所声明的异常完全匹配, 派生类的对象也可以匹配基类的处理程序:

class Annoyance extends Exception {}

class Sneeze extends Annoyance {}

class Human {

public static void main(String[] args) {

try {

throw new Sneeze();

} catch (Sneeze s) {

System.out.println("Caught Sneeze");

} catch (Annoyance a) {

System.out.println("Caught Annoyance");

}

try {

throw new Sneeze();

} catch (Annoyance a) {

System.out.println("Caught Annoyance");

}

}

}

输出是

Caught Sneeze

Caught Annoyance

可以看到如果捕获了sneeze异常, 那么下一句就不会再执行了, 而且也可以将这一句去掉也是能运行的, 但是如果交换这两句的话, 就会出现错误, 以为这样第二个catch子句就永远无法访问了.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值