04 异常与构造器

1 构造器中的异常

一般的资源清理会放置在 finally 块中(例如文件关闭),但是如果在构造器中对象的初始化失败(例如文件未找到),那么就不存在所谓的资源清理。因此,应该从逻辑上保证资源的正确初始化,然后可以在 finally 块中完成清理工作。以文件读取为例:

package com.hcong.exceptions;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * @Classname InputFile
 * @Date 2023/4/18 19:50
 * @Created by HCong
 */
public class InputFile {
    private BufferedReader in;

    public InputFile(String fname) throws FileNotFoundException {
        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 ioException) {
                System.out.println("in.close() unsuccessful");
            }

            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");
        }
    }
}

class Cleanup {
    public static void main(String[] args) {
        try {
            InputFile in = new InputFile("E:\\Projects\\IdeaProjects\\OnJava\\src\\com\\hcong\\streams\\Cheese.dat");
            try {
                String s;
                int i = 1;
                while ((s = in.getLine()) != null) {
                    System.out.println(s);
                }
            } 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");
        }
    }
}

Not much of a cheese shop really, is it?
Finest in the district, sir.
And what leads you to that conclusion?
Well, it's so clean.
It's certainly uncontaminated by cheese.
dispose() successful

总结出的基本规则是:在创建需要清理的对象之后,立即进入一个 try-finally 语句块。当然,最好不要创建抛出异常的构造器。

2 示例

package com.hcong.exceptions;

/**
 * @Classname CleanupIdiom
 * @Date 2023/4/18 20:13
 * @Created by HCong
 */

class ConstructionException extends Exception {
}

// 构造器不会抛出异常
class NeedsCleanup {
    private static long counter = 1;
    private final long id = counter++;

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

// 构造器能抛出异常
class NeedsCleanup2 extends NeedsCleanup {
    NeedsCleanup2() throws ConstructionException {
    }
}

public class CleanupIdiom {
    public static void main(String[] args) {
        // [1]:创建对象后,立即跟 try finally 块
        NeedsCleanup nc1 = new NeedsCleanup();
        try {
            // ...
        } finally {
            nc1.dispose();
        }

        // [2]:为了构造和清理,可以看到将具有不能失败的构造器的对象分组在一起
        NeedsCleanup nc2 = new NeedsCleanup();
        NeedsCleanup nc3 = new NeedsCleanup();
        try {
            // ...
        } finally {
            nc2.dispose();
            nc3.dispose(); // Reverse order of constructionnc2.dispose();
        }

        // [3]:如果对象可能抛出异常,那么需要层层清理
        try {
            NeedsCleanup2 nc4 = new NeedsCleanup2();
            try {
                NeedsCleanup2 nc5 = new NeedsCleanup2();
                try {
                    // ...
                } finally {
                    nc5.dispose();
                }
            } catch (ConstructionException e) {
                // nc5 const.
                System.out.println(e);
            } finally {
                nc4.dispose();
            }
        } catch (ConstructionException e) {
            // nc4 const.
            System.out.println(e);
        }
    }
}

NeedsCleanup 1 disposed
NeedsCleanup 2 disposed
NeedsCleanup 3 disposed
NeedsCleanup 5 disposed
NeedsCleanup 4 disposed

你可能感兴趣的:(OnJava,#,十五,异常,java)