【问题标题】:Throwing exceptions at the correct time在正确的时间抛出异常
【发布时间】:2011-05-17 22:42:12
【问题描述】:

刚刚遇到一个相当混乱的考试题,我的讲师在假期外出,所以我来 StackOverflow 寻求帮助!

问题如下:

“Joe 有自己的 JoeConnection 类,用于在他的计算机和其他计算机之间建立连接。该类提供以下构造函数和实例方法:

JoeConnection( String address ): Make a connection with the URL address.
void writeLn( String text ) : Write text to the JoeConnection.
String readLn( ): Read a line of text from the JoeConnection.
void clode( ) : Close the JoeConnection.

Joe 的连接经常失败,这会导致错误。使用正确的异常处理,演示如何使用 Joe 的 JoeConnection 类来

  1. 使用 URL http://students.chat.box 创建一个 JoeConnection
  2. 向 JoeConnection 写入“Hello world”
  3. 从 JoeConnection 中读取一个字符串
  4. 关闭连接。

连接处理应尽可能详细地提供有关失败原因的详细信息,并打印导致失败的堆栈跟踪。

我不知道如何解决这个问题,但我认为它与此类似:

public class Test {
    try { 
        JoeConnection connection = new JoeConnection(http://students.chat.box); 
    } catch {
        connectionError e; printStacktrace();}
    }
}

谁能帮我解决这个问题?非常感谢。

【问题讨论】:

  • 不确定我是否理解。您在为考试寻求帮助吗?
  • 这是带回家的考试吗?我不认为你所做的在学术上是诚实的。如果这是针对您已经评分的考试,而您只是要求澄清,那就另当别论了。
  • 不,这是多年前在试卷上提出的问题。我已经有几天没有参加考试了,希望能从现在到那时学习如何解决类似的问题。

标签: java exception exception-handling error-handling


【解决方案1】:

没有说明什么异常被抛出以及为什么,唯一的正确异常处理是no处理一点也不。如果您不知道如何解决引发异常的问题,请不要捕获异常。

但你的作业中的进一步说明引入了一个不同的“正确”概念。您应该打印堆栈跟踪。所以捕获异常并打印堆栈跟踪。你在正确的轨道上,但你的语法是错误的。回顾你的教科书和讲义,提醒自己捕捉异常的语法是什么(以及将字符串传递给函数,就此而言)。

try {
  JoeConnection connection = new JoeConnection("http://students.chat.box");
  connection.writeLn("Hello world");
  // etc
} catch (Exception e) {
  e.printStackTrace();
}

【讨论】:

    【解决方案2】:

    “正确的异常处理”有点含糊。我同意@Rob Kennedy 的说法,即除非您知道抛出异常的原因以及应该如何处理,否则任何异常处理都不合适。否则,应该允许异常传播。所以,例如:

    void foo(String address) throws JoeException {
        JoeConnection connection = new JoeConnection(address);
        try {
            connection.writeLn("Hello World!");
        } finally {
            // Ensure the connection is closed when finished.
            // This happens whether an exception occurs or not.
            connection.close();
        }
    }
    

    如果你想捕获异常只是为了打印它,你可以这样做:

    void foo(String address) throws JoeException {
        try {
            JoeConnection connection = new JoeConnection(address);
            try {
                connection.writeLn("Hello World!");
            } finally {
                connection.close();
            }
        } catch (JoeException e) {
            e.printStackTrace();
            // Don't know what to do about this; rethrow.
            throw e;
        }
    }
    

    这里有一个微妙之处,即使是经验丰富的 Java 程序员也可能会错过。如果在创建连接时发生异常,则不需要关闭它。如果写入连接时发生异常,确实需要关闭;因此finally 子句。但是,关闭的行为也可能引发异常。如果关闭连接引发异常,try 语句只会引发该异常。如果由于writeLn 操作引发异常而到达finally 子句,则writeLn 调用的异常将被有效忽略。这可能不是你想要的。

    相反,我们可以尝试一些丑陋的东西:

    void foo(String address) throws JoeException {
        try {
            JoeConnection connection = new JoeConnection(address);
            boolean normalCompletion = false;
            try {
                connection.writeLn("Hello World!");
                normalCompletion = true;
            } finally {
                if (normalCompletion) {
                    // The writeLn operation completed normally.
                    // Propagate an exception thrown by the close operation.
                    connection.close();
                } else {
                    // The writeLn operation completed abruptly.
                    // Ignore an exception thrown by the close operation.
                    try {
                        connection.close();
                    } catch (JoeException e) {
                        /* empty */
                    }
                }
            }
        } catch (JoeException e) {
            e.printStackTrace();
            // Don't know what to do about this; rethrow.
            throw e;
        }
    }
    

    这看起来(并且是)在语法上很可怕,但它确实显示了某种“正确”的异常处理。来自Project Coin 的语言增强应该会清理一下。

    【讨论】:

    • 想为您分离 try-finally 和 try-catch 投票,但由于使用了 log 和 rethrow 而不能。记录或重新抛出,而不是两者兼而有之。
    • @ILMTitan:感谢您的投票建议,并同意记录或重新抛出(作为一般情况下的最佳实践)。但是,这里的“记录”是由于在原始问题中需要打印堆栈跟踪;它与重新抛出相结合,因为如果您不知道为什么抛出异常或如何处理它,则不捕获异常是“处理”异常的适当方式。
    【解决方案3】:

    对于初学者,我可以帮助您了解您所写内容的语法:

    try {
        JoeConnection connection = new JoeConnection("http://students.chat.box");
    }
    catch (JoeConnectionException e) {
        e.printStacktrace();
    }
    

    我冒昧地更改了换行符并将“connectionError”重命名为 JoeConnectionException,这对我来说看起来更传统。

    您必须对 readLn、writeLn 和 close 方法调用执行类似的操作,因为它表示连接经常失败(即不仅仅是在连接时)。

    干杯,祝你好运。

    【讨论】:

      【解决方案4】:

      捕获异常应如下所示:

      try {
          JoeConnection conn = new JoeConnection(url);
      } catch (YourExceptionClassNameHere e) {
          e.printStackTrace();
      }
      

      另外:如果您想使用文字字符串,请确保包含引号。 (应该是“http://students.chat.box”。)

      【讨论】:

        【解决方案5】:

        有一个finally 也很好:

        public class Test {
        
            try { 
                JoeConnection connection = new JoeConnection(http://students.chat.box); 
            } 
        
            catch(Exception e) {
                e.printStacktrace();
            }
        
            finally {
               if(connection != null) {
                  connection.close();
               }
            }
        }
        

        如果您知道如何处理异常,通常会处理它们(这涉及错误恢复逻辑或包装异常并将其抛出到更高级别)。

        假设每个方法都抛出一个异常,你可以为“最大细节”做这样的事情:

        public class Test {
        
            JoeConnection connection = null;
        
            try {
               connection = new JoeConnection("http://students.chat.box");  
               ...
               ...           
            } 
        
            catch(OpenException e) {
               System.out.println("Error while opening connection");
               e.printStacktrace();
            }    
        
            catch(WriteException e) {
               System.out.println("Error while writing to connection");
               e.printStacktrace();
            }
        
            catch(ReadException e) {
               System.out.println("Error while reading from connection");
               e.printStacktrace();
            }
        
            finally {
               if(connection != null) {
                  connection.close();
               }
            }
        }
        

        【讨论】:

        • connection 超出了 finally 块的范围;这将导致编译器错误
        • 糟糕。会修复。我忘了把它从try拉出来。
        猜你喜欢
        • 1970-01-01
        • 2015-05-07
        • 1970-01-01
        • 1970-01-01
        • 2013-05-24
        • 1970-01-01
        • 2011-02-13
        • 2022-01-01
        • 2021-01-20
        相关资源
        最近更新 更多