`
yuxingfirst
  • 浏览: 50581 次
  • 性别: Icon_minigender_1
  • 来自: 湘潭
社区版块
存档分类
最新评论

对于构造方法有可能产生异常的情况下垃圾清理问题的研究

    博客分类:
  • Java
 
阅读更多

有时候我们可能会问:“当异常发生的时候,所有的东西都会被正确的清除吗?”,大多数情况下是相当安全的,不过在涉及到构造方法的时候问题就出现了。通常,构造器会把对象设置成安全的初始状态,但是它也可能会执行某些操作,比如,打开一个在使用完对象以及调用特定的清理方法之前不需要进行垃圾清理的文件。如果实在构造器了抛出异常,那么这么垃圾清理方法可能不会被正确执行,这就意味着在写你的构造方法的时候你必须十分用心。

           也许你会把 finally 作为一种解决方案,但事实并不如此简单,应为finally在每次进行清理时都会执行一次。试想,如果一个构造器在它执行的过程中失败了,这样,这个对象的某些成员它并 没有成功创建,然而,在finally子句中这些部分也是要被清理的,这就是一个缺陷。

如下面这个例子:

package chapter12;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class InputFile {
					private BufferedReader in;
					public InputFile(String fname) throws Exception {
						try {
							in = new BufferedReader(new FileReader(fname));
							// Other code that might throw exceptions
						} catch (FileNotFoundException e) {
							System.out.println("Could not open " + fname);
							// Wasn’t open, so don’t close it
							throw e;
						} catch (Exception e) {
						// All other exceptions must close it
						try {
							in.close();
						} catch (IOException e2) {												   System.out.println("in.close()unsuccessful");                               
						}
						throw e; // Rethrow
						} finally {
						// Don’t close it here!!!
						}
				}
				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");
		}
	}
}
 这个类很简单,也很容易理解。如果在InputFile的构造方法里抛出了FileNotFoundException,则说明文件没有被成功打开,因而,in这个BufferedReader的对象实例没有成功创建,此时如果在finally里面这样写 in.close(),这就是不合理的。所以在构造方法抛出FileNotFoundException时,我们并不需要调用in.close()对象,因为它没有关联到一个具体的文件上;不过当抛出其他Excpetion时,我们就需要关闭文件了,因为这时指定的文件已成功打开。另外需要说明的是dispose方法,这个方法是你在使用完InputFile对象之后需要调用的,它用来释放系统资源(例如文件句柄)。可能你会想到把这个功能放到finalize方法里面,然而我们知道我们无法确定finalize方法是否总是会被调用,即便会被调用我们也无法确定会在什么时候调用。从这里就牵扯出java语言的一个缺陷,在java里面只有内存的清理是自动执行的,除此之外其他的一切都不会自动清除,所以我们要通知客户端程序员dispose方法是有一定的职责的。

    在构造方法可能抛出异常的情况下,比较安全的做法是使用嵌套的try,比如下面所演示的:

public class Cleanup {
	public static void main(String[] args) {
		try {
			InputFile in = new InputFile("Cleanup.java");
			try {
				String s;
				int i = 1;
				while ((s = in.getLine()) != null)
					; // Perform line-by-line processing here...
			} catch (Exception e) {
				System.out.println("Caught Exception in main");
				e.printStackTrace(System.out);
			} finally {
				in.dispose();
			}
		} catch (Exception e) {
			System.out.println("InputFile construction failed");
		}
	}
}
 这个程序的逻辑不难分析。InputFile构造器内部的try块是可以生效的,当在构造方法里产生了异常,则会进入上面例子中外部的try块的catch子句,这是不用执行dispose方法;不过要是InputFile对象实例成功被构造,那么在内部的try块里就必须要执行dispose方法。按照上面程序段的写法就可以保证:只要InputFile的对象被成功创建,那么一定会执行dispose方法,释放系统资源。

       对于构造方法可能会抛出异常的情况,通用的习惯用法是:在需要进行清理的对象被创建后,立即接上try-finally块,如下面的代码所示:

package chapter12;

class NeedsCleanup { // Construction can’t fail
	private static long counter = 1;
	private final long id = counter++;

	public void dispose() {
		System.out.println("NeedsCleanup " + id + " disposed");
	}
}

class ConstructionException extends Exception {
}

class NeedsCleanup2 extends NeedsCleanup {
	// Construction can fail:
	public NeedsCleanup2() throws ConstructionException {
	}
}

public class CleanupIdiom {
	public static void main(String[] args) {
		// Section 1:
		NeedsCleanup nc1 = new NeedsCleanup();
		try {
			// ...
		} finally {
			nc1.dispose();
		}
		// Section 2:
		// If construction cannot fail you can group objects:
		NeedsCleanup nc2 = new NeedsCleanup();
		NeedsCleanup nc3 = new NeedsCleanup();
		try {
			// ...
		} finally {
			nc3.dispose(); // Reverse order of construction
			nc2.dispose();
		}
		// Section 3:
		// If construction can fail you must guard each one:
		try {
			NeedsCleanup2 nc4 = new NeedsCleanup2();
			try {
				NeedsCleanup2 nc5 = new NeedsCleanup2();
				try {
					// ...
				} finally {
					nc5.dispose();
				}
			} catch (ConstructionException e) { // nc5 constructor
				System.out.println(e);
			} finally {
				nc4.dispose();
			}
		} catch (ConstructionException e) { // nc4 constructor
			System.out.println(e);
		}
	}
}
 按照这种写法,可以看出:对于那些构造方法不会产生异常的类,我们总能对它进行清理;对于构造方法有可能产生异常的类,我们总能在必要时对它进行清理。

0
0
分享到:
评论

相关推荐

    模拟实现垃圾文件清理工具

    此时,需要合理处理这些异常情况,向用户提供友好的错误提示。 6. **设置和选项**:为了提高用户体验,垃圾文件清理工具应允许用户自定义清理规则,如设置排除目录、选择清理级别等。这可以通过对话框或选项卡界面...

    垃圾填埋场选址方法研究.pdf

    这三种方法各有优势,AHP便于处理复杂问题,但可能受到主观判断影响;模糊综合评价法适用于模糊条件,但需要处理不确定性;GIS则能直观呈现空间信息,但依赖于数据质量和分析技巧。综合运用这些方法,能够提高垃圾...

    day09-面向对象-封装&构造方法

    在这种情况下,匿名对象仅用于调用`run()`方法,之后就会变成垃圾,等待垃圾回收器清理。 封装是面向对象的三大特性之一,它隐藏了对象的实现细节,只对外暴露必要的接口。封装的主要目的是提高代码的安全性,减少...

    C++/C#异常处理机制的内存管理策略

    本文深入探讨了C++与C#这两种编程语言中异常处理机制的核心概念,特别是如何在这些机制中处理对象的构造与析构问题,同时分析了在异常处理过程中如何有效地管理内存资源。 #### 关键词 C++, C#, 异常处理, 公共...

    基于支持向量机理论的垃圾邮件过滤模型.PDF

    综上所述,基于支持向量机理论的垃圾邮件过滤模型,尤其是结合模糊支持向量机的方法,能够在处理邮件的模糊性和非对称性方面表现出色,有助于提高邮件过滤的准确性和效率。未来的研究方向可以进一步探索如何更有效地...

    城市垃圾运输问题——数学建模二等奖.pdf

    城市垃圾运输问题是一个复杂的城市规划问题,涉及到交通优化、资源分配和环境管理等多个方面。...这种方法不仅有助于解决当前的问题,也为其他类似的实际问题提供了解决思路,如物流配送、货物运输等。

    C++引用计数设计与分析(解决垃圾回收问题).docx

    由于C++没有内置的垃圾回收机制,程序员需要手动管理内存,这可能导致内存泄漏、悬空指针等问题。然而,C++通过提供构造函数和析构函数,以及一些智能指针的设计,如`std::shared_ptr`和`std::unique_ptr`,来帮助...

    建筑垃圾清运和处置方案.doc

    2.2 建筑垃圾产生情况:明确指出垃圾总量(约4000方)和类型(建筑垃圾、弃料、余泥、废弃物),并提出了消纳方式(密闭式车辆外运)及具体要求,如定期清理、避免乱倒乱卸,保持场地整洁,减少运输过程中的扬尘问题...

    Python构造函数及解构函数介绍

    在使用__del__()时,也需要注意循环引用的问题,这可能导致内存泄漏,因为循环引用的对象永远不会被垃圾回收。 在实际应用中,开发者应当尽量避免在__del__()中执行复杂的操作,因为这可能导致程序的不稳定性。例如...

    Java异常面试题(2022最新版).docx

    - 特点: 如果一个方法可能抛出此类异常,要么在方法签名中通过`throws`关键字声明抛出,要么在方法体内通过`try-catch`结构处理。 - 处理方式: 必须通过声明或捕获的方式来处理,否则编译失败。 #### 三、Java...

    (正式)永登县生活垃圾处理场建设工程岩土工程勘察报告.doc

    永登县生活垃圾处理场建设工程的岩土工程勘察报告是一份详细评估了该工程建设场地地质状况的重要文件。报告的目的是为了确保垃圾处理场的安全、稳定和环保运营,为设计和施工提供科学依据。以下是对报告中关键知识点...

    小组学习:使用构造函数

    在某些情况下,我们可能希望控制对象的创建方式,这时可以使用工厂方法。工厂方法是一种特殊的静态方法,负责创建和返回类的实例。它可以提供更灵活的实例化逻辑,比如条件判断、对象缓存等。 六、构造函数和析构...

    34个java问题.pdf

    构造方法有哪些特性 - 构造方法名与类名相同。 - 没有返回类型。 - 主要用于初始化对象状态。 #### 23. 静态方法和实例方法有何不同 - **静态方法**:不依赖于任何特定对象,可以直接通过类名调用。 - **实例...

    JAVA面试100题.doc

    异常处理通常使用try-catch-finally结构,尝试块中可能会抛出异常的代码会被捕获,catch块处理特定类型的异常,finally块则确保无论是否发生异常都会执行的代码。 【Java接口与C++虚类】 Java接口和C++的虚类在...

    垃圾邮件过滤技术的分析与实现

    面对垃圾邮件带来的挑战,在当前技术条件下,要彻底消除垃圾邮件是比较困难的。但在新的邮件传输协议出现之前,可以通过在SMTP协议基础上综合运用多种过滤技术来识别和过滤垃圾邮件,从而减轻其危害。 ##### 3.1 ...

    城市生活垃圾焚烧过程.doc

    二噁英因其强毒性而尤为关注,它们在高温燃烧条件下可能形成,尤其是在有氯元素和金属催化剂存在的情况下。 2. 二噁英的构造与毒性 二噁英是一类含有氯的三环芳香族有机化合物,由2至4个氯取代的苯环组成,具有...

    机器学习的研究.zip

    案例研究部分可能会涵盖各种实际应用场景,如垃圾邮件过滤、推荐系统、股票预测、医疗诊断、自动驾驶等。通过这些案例,我们可以了解机器学习如何在不同领域发挥其价值,并掌握将理论应用于实际问题的技巧。 总的来...

    Python:通用异常类型表

    6. **GeneratorExit**:生成器(generator)在某些情况下需要异常来通知其退出,例如`next()`调用在一个已关闭的生成器上,或者在生成器外部抛出`GeneratorExit`。 7. **StandardError**:所有的内建标准异常的基类,...

Global site tag (gtag.js) - Google Analytics