`
岁月如歌
  • 浏览: 107228 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Exception Handling Templates in Java(java异常处理模板)

    博客分类:
  • java
阅读更多

Before you read this text, it is a good idea to have read the text "Fail Safe Exception Handling".

Correct exception handling code can be tedious to write. Try-catch blocks also clutter the code and makes it harder to read. Look at the example below:

    Input       input            = null;
    IOException processException = null;
    try{
        input = new FileInputStream(fileName);

        //...process input stream...
    } catch (IOException e) {
        processException = e;
    } finally {
       if(input != null){
          try {
             input.close();
          } catch(IOException e){
             if(processException != null){
                throw new MyException(processException, e,
                  "Error message..." +
                  fileName);
             } else {
                throw new MyException(e,
                    "Error closing InputStream for file " +
                    fileName;
             }
          }
       }
       if(processException != null){
          throw new MyException(processException,
            "Error processing InputStream for file " +
                fileName;
    }

In this example no exceptions are lost. If an exception is thrown from within the try block, and another exception is thrown from the input.close() call in the finally block, both exceptions are preserved in the MyException instance, and propagated up the call stack.

That is how much code it takes to handle the processing of an input stream without any exceptions being lost. In fact it only even catches IOExceptions. RuntimeExceptions thrown from the try-block are not preserved, if the input.close() call also throws an exception. Isn't it ugly? Isn't it hard to read what is actually going on? Would you remember to write all that code everytime you process an input stream?

Luckily there is a simple design pattern, the Template Method, that can help you get the exception handling right everytime, without ever seeing or writing it in your code. Well, maybe you will have to write it once, but that's it.

What you will do is to put all the exception handling code inside a template. The template is just a normal class. Here is a template for the above input stream exception handling:

public abstract class InputStreamProcessingTemplate {

    public void process(String fileName){
        IOException processException = null;
        InputStream input = null;
        try{
            input = new FileInputStream(fileName);

            doProcess(input);
        } catch (IOException e) {
            processException = e;
        } finally {
           if(input != null){
              try {
                 input.close();
              } catch(IOException e){
                 if(processException != null){
                    throw new MyException(processException, e,
                      "Error message..." +
                      fileName);
                 } else {
                    throw new MyException(e,
                        "Error closing InputStream for file " +
                        fileName;
                 }
              }
           }
           if(processException != null){
              throw new MyException(processException,
                "Error processing InputStream for file " +
                    fileName;
        }
    }

    //override this method in a subclass, to process the stream.
    public abstract void doProcess(InputStream input) throws IOException;
}

All the exception handling is encapulated inside the InputStreamProcessingTemplate class. Notice how the process() method calls the doProcess() method inside the try-catch block. You will use the template by subclassing it, and overriding the doProcess() method. To do this, you could write:

    new InputStreamProcessingTemplate(){
        public void doProcess(InputStream input) throws IOException{
            int inChar = input.read();
            while(inChar !- -1){
                //do something with the chars...
            }
        }
    }.process("someFile.txt");

This example creates an anonymous subclass of the InputStreamProcessingTemplate class, instantiates an instance of the subclass, and calls its process() method.

This is a lot simpler to write, and easier to read. Only the domain logic is visible in the code. The compiler will check that you have extended the InputStreamProcessingTemplate correctly. You will typically also get more help from your IDE's code completion when writing it, because the IDE will recognize both the doProcess() and process() methods.

You can now reuse the InputStreamProcessingTemplate in any place in your code where you need to process a file input stream. You can easily modify the template to work for all input streams and not just files.

 

Using Interfaces Instead of Subclassing

Instead of subclassing the InputStreamProcessingTempate you could rewrite it to take an instance of an InputStreamProcessor interface. Here is how it could look:

public interface InputStreamProcessor {
    public void process(InputStream input) throws IOException;
}


public class InputStreamProcessingTemplate {

    public void process(String fileName, InputStreamProcessor processor){
        IOException processException = null;
        InputStream input = null;
        try{
            input = new FileInputStream(fileName);

            processor.process(input);
        } catch (IOException e) {
            processException = e;
        } finally {
           if(input != null){
              try {
                 input.close();
              } catch(IOException e){
                 if(processException != null){
                    throw new MyException(processException, e,
                      "Error message..." +
                      fileName;
                 } else {
                    throw new MyException(e,
                        "Error closing InputStream for file " +
                        fileName);
                 }
              }
           }
           if(processException != null){
              throw new MyException(processException,
                "Error processing InputStream for file " +
                    fileName;
        }
    }
}

Notice the extra parameter in the template's process() method. This is the InputStreamProcessor, which is called from inside the try block (processor.process(input)). Using this template would look like this:

    new InputStreamProcessingTemplate()
        .process("someFile.txt", new InputStreamProcessor(){
            public void process(InputStream input) throws IOException{
                int inChar = input.read();
                while(inChar !- -1){
                    //do something with the chars...
                }
            }
        });

It doesn't look much different from the previous usage, except the call to the InputStreamProcessingTemplate.process() method is now closer to the top of the code. This may be easier to read.

 

Static Template Methods

It is also possible to implement the template method as a static method. This way you don't need to instantiate the template as an object every time you call it. Here is how the InputStreamProcessingTemplate would look as a static method:

public class InputStreamProcessingTemplate {

    public static void process(String fileName,
    InputStreamProcessor processor){
        IOException processException = null;
        InputStream input = null;
        try{
            input = new FileInputStream(fileName);

            processor.process(input);
        } catch (IOException e) {
            processException = e;
        } finally {
           if(input != null){
              try {
                 input.close();
              } catch(IOException e){
                 if(processException != null){
                    throw new MyException(processException, e,
                      "Error message..." +
                      fileName);
                 } else {
                    throw new MyException(e,
                        "Error closing InputStream for file " +
                        fileName;
                 }
              }
           }
           if(processException != null){
              throw new MyException(processException,
                "Error processing InputStream for file " +
                    fileName;
        }
    }
}

The process(...) method is simply made static. Here is how it looks to call the method:

    InputStreamProcessingTemplate.process("someFile.txt",
        new InputStreamProcessor(){
            public void process(InputStream input) throws IOException{
                int inChar = input.read();
                while(inChar !- -1){
                    //do something with the chars...
                }
            }
        });

Notice how the call to the template's process() method is now a static method call.

 

Summary

Exception handling templates are a simple yet powerful mechanism that can increase the quality and readability of your code. It also increases your productivity, since you have much less code to write, and less to worry about. Exceptions are handled by the templates. And, if you need to improve the exception handling later in the development process, you only have a single spot to change it in: The exception handling template.

The Template Method design pattern can be used for other purposes than exception handling. The iteration of the input stream could also have been put into a template. The iteration of a ResultSet in JDBC could be put into a template. The correct execution of a transaction in JDBC could be put into a template. The possibilities are endless.

Context reuse and templates are also discussed in the article Code Reuse: Context and Action Reuse.

分享到:
评论

相关推荐

    几款不错的JAVA后台模板

    例如,使用Log4j或SLF4J进行日志记录,使用Exception Handling来捕获和处理异常。 7. **性能优化**:后台模板可能集成了缓存机制,如Redis或Memcached,以提升数据读取速度。同时,使用Gzip压缩、CDN内容分发网络等...

    c++-for-java

    C++中的模板(templates)和异常处理(exception handling)也是需要特别关注的部分,因为这些在Java中也有相应的概念,但实现和用法可能有所不同。 由于文件提到文档目前还处于草案阶段,建议Java程序员在学习C和...

    C++帮助文档(相当于一个简单的java aPI)

    4. **异常处理(Exception Handling)** C++支持异常处理机制,通过 `try`、`catch` 和 `throw` 关键字来捕获和处理运行时错误。理解何时和如何使用异常处理能帮助编写健壮的代码。 5. **模板(Templates)** ...

    FreeMarker编程指南

    5. **异常处理 (Exception Handling):** - 配置异常处理策略,如忽略模板加载错误等。 #### 六、其他说明 1. **变量 (Variables):** - 如何声明和使用变量。 2. **字符编码 (Character Encoding):** - 设置...

    struts2.0.11.rar_Java编程_Java_

    7. **异常处理(Exception Handling)**:Struts2提供了全局和局部的异常处理机制,可以优雅地处理程序中的错误和异常。 8. **国际化(Internationalization, I18N)**:Struts2支持多语言,方便开发面向全球用户的...

    c++编程思想.第2卷.实用编程技术

    3. **异常处理(Exception Handling)**:异常处理是C++中用于错误处理的一种机制,通过try、catch和throw关键字,可以在程序运行时捕获和处理错误,保证程序的健壮性。 4. **命名空间(Namespaces)**:命名空间是...

    移动QQ源码

    在移动QQ源码中,你可能会看到C++的一些核心特性,如类(class)、对象(object)、继承(inheritance)、多态(polymorphism)等面向对象编程概念,以及模板(templates)、异常处理(exception handling)、STL...

    sping rest

    7. **Exception Handling**:使用 `@ExceptionHandler` 注解可以定义全局或特定异常的处理逻辑,返回自定义的错误信息。 8. **HATEOAS**:HATEOAS(Hypermedia as the Engine of Application State)是 REST 架构的...

    add-variety-cpp-Akshay3012:GitHub Classroom创建的add-variety-cpp-Akshay3012

    4. **异常处理(Exception Handling)**:当满足特定条件时触发警报可能涉及到异常处理。在C++中,可以使用`try-catch`块来捕获和处理可能出现的异常。如果数据不符合预期或存在错误,抛出一个异常并由相应的`catch`...

    Codechef_Long:Codechef Long Challange

    C++的特点包括类(classes)、模板(templates)、异常处理(exception handling)以及STL(Standard Template Library),这些特性使得C++能够创建高效且易于维护的代码。 Codechef Long Challenge的题目涵盖了...

    2020CCE.class

    异常处理(Exception Handling)也是C++中处理错误和异常情况的重要机制。 总之,“2020CCE.class”这个文件名可能代表了一次关于C++编程的教育活动,其中涵盖了面向对象编程的核心概念。通过学习和理解类(Class)...

Global site tag (gtag.js) - Google Analytics