java 构造器(constructor)
有一点很重要,即你要时刻询问子句"如果异常发生了,所有东西能被正确清理码?",尽管大多数情况下时非常安全的,但涉及到构造器时,问题出现了,构造器会把对象设置成安全的初始状态,但还会又别的动作,比如打开一个文件,这样的动作只有在对象使用完毕并且用户调用了特殊的清理方法之后才能得以清理,如果在构造器内抛出了异常,这些行为也许就不能正常工作了,这意味着在编写构造器时要格外细心.
用finally也许可以解决问起,但问题并非如此简单,因为finally会每次都执行清理操作,如果构造器在执行过程中半途而废,也许该对象的某部分还没有创建成功就要被清理,这又会抛出新的异常(.close()也会抛出异常)
1.构造器抛出异常要格外注意清理方法是否有必要调用,如果方法恰当,直接向上层抛出的确能简化编程
- package exceptions;
- //: exceptions/InputFile.java
- // Paying attention to exceptions in constructors.
- import java.io.*;
- 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()也可能抛出异常,所有要放到try块里面
- in.close();
- } catch(IOException e2) {
- System.out.println("in.close() unsuccessful");
- }
- throw e; // Rethrow
- } finally { //由于finally总会被执行,如果在这里关闭文件则文件刚打开还没开始使用就关闭了
- // Don't close it here!!!
- }
- }
- public String getLine() {
- String s;
- try {
- s = in.readLine();
- } catch(IOException e) { //这这异常已被捕获,因此getLine不会抛出任何异常
- 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");
- }
- }
- } ///:~
2.对于在构造器阶段可能抛出的异常,并且要求清理的,最安全的使用方法时使用嵌套的try子句,
- package exceptions;
- //: exceptions/Cleanup.java
- // Guaranteeing proper cleanup of a resource.
- 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) {//这里捕捉的时getLine()方法重新抛出的异常
- System.out.println("Caught Exception in main");
- e.printStackTrace(System.out);
- } finally { //如果构造成功,则一定会执行in.dispose()清理
- in.dispose();
- }
- } catch(Exception e) { //InputFile对象在自己的try语句块优先,因此构造失败会进入这里,而不会执行内部的try块的in.colse()
- System.out.println("InputFile construction failed");
- }
- }
- } /* Output:
- dispose() successful
- *///:~
3. 这种通用的清理惯用法在构造器不跑出任何异常时也应该应用,其基本规则时:在需要清理的对象之后,立即进入一个try-finally语句块.
- //基本上,你应该仔细考虑所有的可能细节,例如本例的dispose()如果可以抛出异常,那么就需要额外的try语句块
package exceptions;- //: exceptions/CleanupIdiom.java
- // Each disposable object must be followed by a try-finally
- 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:
- // nc5 constructor 如果对象构造不能失败就不需要任何catch
- //不能失败的对象构造器对象可以群众在一起
- 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 { //如果nc5对象构造失败则会调用try块清理,否则永不调用
- // ...
- } finally {
- nc5.dispose();
- }
- } catch(ConstructionException e) {
- System.out.println(e);
- } finally {
- nc4.dispose();
- }
- } catch(ConstructionException e) { // nc4 constructor
- System.out.println(e);
- }
- }
- } /* Output:
- NeedsCleanup 1 disposed
- NeedsCleanup 3 disposed
- NeedsCleanup 2 disposed
- NeedsCleanup 5 disposed
- NeedsCleanup 4 disposed
- *///:~
java 构造器(constructor)的更多相关文章
- Java 构造器Constructor 继承
Java默认构造方法 构造方法作用:初始化所定义的类的对象和属性. 构造方法没有返回类型. 2 继承中的构造器 子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式). 如果父类 ...
- 【Java面试题】7 构造器Constructor是否可被override?
构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload. Constructor不能被继承,所以Constructor也就不能被override.每一个类必 ...
- JAVA 构造器, extends[继承], implements[实现], Interface[接口], reflect[反射], clone[克隆], final, static, abstrac
记录一下: 构造器[构造函数]: 在java中如果用户编写类的时候没有提供构造函数,那么编译器会自动提供一个默认构造函数.它会把所有的实例字段设置为默认值:所有的数字变量初始化为0;所有的布尔变量设置 ...
- Effective Java - 构造器私有、枚举和单例
目录 饿汉式单例 静态常量 静态代码块 懒汉式单例 尝试加锁 同步代码块 双重检查 静态内部类单例 枚举单例 Singleton 是指仅仅被实例化一次的类.Singleton代表了无状态的对象像是方法 ...
- JAVA构造器,重载与重写
1. java构造器 构造器也叫构造方法(constructor), 用于对象初始化. 构造器是一个创建对象时被自动创建的特殊方法,目的是对象的初始化. 构造器 的名称与类的名称一致. JAVA通过n ...
- 简单介绍 Java 构造器
导读 构造器是编程的强大组件.使用它们来释放 Java 的全部潜力. 在开源.跨平台编程领域,Java 无疑(?)是无可争议的重量级语言.尽管有许多伟大的跨平台框架,但很少有像 Java 那样统一和直 ...
- 浅谈Java构造器
Java构造器 每个类都有构造方法.如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认构造方法. 在创建一个对象的时候,至少要调用一个构造方法.构造方法的名称必须与类同名,一个类可以 ...
- 构造器Constructor是否可被override?
构造器Constructor是否可被override? 构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading.
- scjp考试准备 - 7 - Java构造器
题目——如下代码的执行结果: class Hello{ String title; int value; public Hello(){ title += " World!"; } ...
随机推荐
- DELPHI 字符串与日期格式互转
procedure TForm1.Button1Click(Sender: TObject); var D:TDateTime; s:string; begin D:=VarToDateTime('0 ...
- Racket里的方括号
Racket里的方括号 Racket编程指南 https://blog.csdn.net/chinazhangyong/article/category/7386082 来自于QQ群racket!( ...
- 【刷题】LOJ 6002 「网络流 24 题」最小路径覆盖
题目描述 给定有向图 \(G = (V, E)\) .设 \(P\) 是 \(G\) 的一个简单路(顶点不相交)的集合.如果 \(V\) 中每个顶点恰好在 \(P\) 的一条路上,则称 \(P\) 是 ...
- 洛谷 P1412 经营与开发 解题报告
P1412 经营与开发 题目描述 \(4X\)概念体系,是指在\(PC\)战略游戏中一种相当普及和成熟的系统概念,得名自4个同样以"\(EX\)"为开头的英语单词. \(eXplo ...
- CF1110E Magic Stones(构造题)
这场CF怎么这么多构造题…… 题目链接:CF原网 洛谷 题目大意:给定两个长度为 $n$ 的序列 $c$ 和 $t$.每次我们可以对 $c_i(2\le i<n)$ 进行一次操作,也就是把 $c ...
- Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction 异常一例
参考下面的文章,最终找到我的报错原因: 我是在 service中一个以 get开头的方法中,加入了一行数据库数据删除代码,因为 spring的事务配置中,配置了get开头的方法 是 readonle的 ...
- os.path.splitext()用法--分离文件名与扩展名
用法: os.path.splitext(“文件路径”) 分离文件名与扩展名:默认返回(fname,fextension)元组,可做分片操作 例子: import os path_01='E:\ ...
- Python模块调用方式详解
Python模块调用方式详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其 ...
- 函数和常用模块【day05】:装饰器前奏(一)
本节内容 定义 原则 实现装饰器的储备知识 函数及变量 高阶函数 一.定义 1.装饰器:本质是函数. 2.功能:用来装饰其他函数,顾名思义就是,为其他的函数添加附件功能的. 二.原则 不能修改被装饰函 ...
- bzoj千题计划255:bzoj3572: [Hnoi2014]世界树
http://www.lydsy.com/JudgeOnline/problem.php?id=3572 明显需要构造虚树 点属于谁管理分三种情况: 1.属于虚树的点 2.在虚树上的边上的点 3.既不 ...