26. finally与中断
//该方法返回false
static boolean f() {
try {
return true;
} finally {
return false;
}
}
不要用return、break、continue或throw来退出finally语句块,并且千万不要允许受检查的异常传播到finally语句
块之外。也就是说不要在finally块内终止程序,而是执行完finally块后,要将控制权移交给try块,由try最终决定
怎样结束方法的调用。
对于任何在finally语句块中可能抛出的受检查异常都要进行处理,而不是任其传播,下面流拷贝程序在关闭流时没有
防止异常的传播,这会有问题:
static void copy(String src, String dest) throws IOException {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(src);
out = new FileOutputStream(dest);
byte[] buf = new byte[1024];
int n;
while ((n = in.read(buf)) >= 0) {
out.write(buf, 0, n);
}
} finally{
//这里应该使用try-catch将每个close包装起来
if(in != null){in.close();}
if(in != null){out.close();}
}
}
catch块中的return语句是不会阻止finally块执行的,那么catch块中的continue和break能否阻止?答案是不会的,
与return一样,finally语句块是在循环被跳过(continue)和中断(break)之前被执行的:
int i = 0;
System.out.println("--continue--");
while (i++ <= 1) {
try {
System.out.println("i=" + i);
continue;
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
System.out.println("--break--");
while (i++ <= 3) {
try {
System.out.println("i=" + i);
break;
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
27. catch捕获异常规则
捕获RuntimeException、Exception或Throwable的catch语句是合法,不管try块里是否抛出了这三个异常。但如果try
块没有抛出或不可能抛出检测性异常,则catch不能捕获这些异常,如IOException异常:
public class Test {
public static void main(String[] args) {
try{
//...
}catch (Exception e) {
}catch (Throwable e) {
}
/* !! 编译出错
try{
//...
}catch (IOException e) {
}
*/
}
}
28. 重写时方法异常范围
重写或实现时不能扩大异常的范围,如果是多实现,则异常取所有父类方法异常的交集或不抛出异常:
interface I1 {
void f() throws Exception;
}
interface I2 {
void f() throws IOException;
}
interface I3 extends I1, I2 {}
class Imp implements I3 {
// 不能编译通过,多继承时只能取父类方法异常交集,这样就不会扩大异常范围
// !! void f () throws Exception;
// void f();// 能编译通过
// 能编译通过,Exception与IOException的交集为IOException
public void f() throws IOException {
}
}
29. 静态与非静态final常量不能在catch块中初始化
静态与非静态块中如果抛出了异常,则一定要使用try-catch块来捕获。
public class Test {
static final int i;
static {
try {
i = f();
} catch (RuntimeException e) {
i = 1;
}
}
static int f() {
throw new RuntimeException();
}
}
上面的程序编译不能通过。表面上是可以的,因为i第一次初始化时可能抛出异常,所以抛异常时可以在catch块中初
始化,最终还是只初始化一次,这正是空final所要求的,但为什么编译器不知道这些呢?
要确定一个程序是否不止一次地对一个空final进行赋值是很困难的问题。语言规范在这一点上采用了保守的方式。
30. System.exit()与finally
try {
System.out.println("Hello world");
System.exit(0);
// 或者使用Runtime退出系统
// Runtime.getRuntime().exit(0);
} finally {
System.out.println("Goodbyte world");
}
上面的程序会打印出"Goodbyte world"吗?不会。
System.exit将立即停止所有的程序线程,它并不会使finally语句块得到调用,但是它在停止VM之前会执行关闭挂钩
操作(这此挂钩操作是注册到Runtime.addShutdownHook上的线程),这对于释放VM之外的资源很有帮助。使用挂钩程
序修改上面程序:
System.out.println("Hello world");
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("Goodbyte world");
}
});
System.exit(0);
另外,对象回收时,使用VM调用对象的finalize()方法有两种:
System.runFinalization():该方法让虚拟机也只是尽最大努力去完成所有未执行的finalize()终止方法,但不一定
会执行。
System.runFinalizersOnExit(true):该方法一定会回收,但不安全,已被废弃。因为它可能对正在使用的对象调用
终结方法,而其他线程同时正在操作这些对象,从而导致不正确的行为或死锁。
为了加快垃圾回收,使用System.gc(),但不一定马上执行加收动作,由虚拟机决定,实质上是调用
Runtime.getRuntime().gc()。
System的很多方法都是调用Runtime类的相关方法来实现的。
31. 递归构造
public class S {
private S instance = new S();
public S() {}
}
如果在程序外面构造该类的实例,则会抛出java.lang.StackOverflowError错误。其原因是实例变量的初始化操作将
先于构造器的程序体而运行。
32. 构造器中的异常
如果父类构造器抛出了检测异常,则子类也只能抛出,而不能采用try-catch来捕获:
public class P {
public P() throws Exception {}
}
class S extends P {
public S() throws Exception {
try {
// 不能在try块中明确调用父类构造器,因为构造的
// 明确调用只能放在第一行
// !! super();
//try-catch不能捕获到父类构造器所抛出的异常,子类只能抛出
} catch (Exception e) {
}
}
}
如果初使化实例属性时抛出了异常,则构造器只能抛出异常,在构造器中捕获不起作用:
public class A {
private String str = String.class.newInstance();
public A() throws InstantiationException, IllegalAccessException {}
public A(int i) throws Exception {
try {//即使这里捕获了,方法签名还是得要抛出
} catch (Exception e) {
}
}
/*
* !!编译不能通过,因为str2为静态的,他不能通过构造器来捕获,所以只
* 能使用静态方法来捕获。即初始化静态成员时不能抛出捕获性异常。
*/
//!!private static String str2 = String.class.newInstance();
// 只能使用静态方法来捕获异常,如果是抛出的运行时异常则不需要捕获
private static String str2 = newInstance();
private static String newInstance() throws RuntimeException {
try {
return String.class.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
33. StackOverflowError
Java虚拟机对栈的深度限制到了某个值,当超过这个值时,VM就抛出StackOverflowError。一般VM都将栈的深度限制
为1024,即当方法调用方法的层次超过1024时就会产生StackOverflowError。
ref:http://jiangzhengjun.iteye.com/blog/652720
分享到:
相关推荐
你认为自己了解Java多少?你是个爱琢磨的代码侦探吗?你是否曾经花费数天时间去追踪一个由Java或其类库的陷阱和缺陷而导致的bug?你喜欢智力测验吗?本书正好适合你!.. Bloch和Gafter继承了Effective Jaya一书的传统,...
本篇将基于“Java解惑”这一主题,详细探讨Java中的常见问题、易错点以及需要注意的细节。 1. **内存管理与垃圾回收** - Java的自动内存管理机制是通过垃圾回收(Garbage Collection, GC)来实现的。理解如何工作...
在“java解惑99”这个主题中,我们可以深入探讨一系列关于Java编程的常见问题和解决方案。这个压缩包文件包含了作者个人对Java编程难题的源码解析和分析,旨在帮助开发者们解决他们在学习和实践中遇到的困难。让我们...
### Java解惑知识点详解 #### 一、表达式谜题:判断奇数的正确方法 在探讨本书提及的第一个“表达式谜题”时,我们首先遇到了一个用来判断一个整数是否为奇数的方法: ```java public static boolean isOdd(int i...
### Java解惑:常见误区与解答 #### 一、判断奇数的方法问题 **知识点概述:** 本节讨论了一个常见的编程误区,即如何正确判断一个整数是否为奇数。通常,开发人员会认为可以通过模运算(%)来判断一个整数是否能...
《Java解惑》是一本专为初学者设计的Java编程指南,它旨在帮助读者深入理解Java语言的基础概念和核心特性,从而轻松入门并逐步提升编程技能。这本书涵盖了从基本语法到高级特性的全面内容,是Java学习者的理想伙伴。...
第3篇为项目实战篇,主要包括讯友联系人管理模块、播客视频管理模块、博客管理模块、明日知道论坛管理模块等4个小型项目:第4篇为商业系统篇,主要包括一个大型的商业项目,即天下淘网上购物商城系统。 《Java Web...
java 仿IPMSG程序,还有些小问题. 1.文件传输速度太慢,可以创建发送和接收缓存提高传输速度,最简单的办法就是加大UDP包大小,设置MyPacket.java 文件里变量...但是丢包的原因一直不太明白,如有达人知道请留言解惑.谢了
* Java 解惑:昊斯特曼Java 解惑 操作系统: * LINUX 教程:布洛克LINUX 教程 :Windows 用户转向 Linux的 12 个步骤 * Linux 私房菜:米勒鸟哥的 Linux私房菜 * 现代操作系统:鸟哥现代操作系统 * 操作系统 - 内核...
2. "JAVA面试题解惑系列.pdf":虽然这个文件名与Oracle执行调度直接关联性不大,但考虑到Java在企业级应用开发中的广泛使用,特别是在与Oracle数据库交互时,这份PDF可能包含了一些关于Java如何连接、操作Oracle...
压缩包内的文件"jsp实验20101013.doc"可能是关于JSP的实验指导或教程,"《IT学生解惑真经》.doc"可能是包含更多编程知识的资料,而"eshop1", "eshop2", "eshop3"很可能是项目的不同版本或模块,"096442"可能是某个...