【问题标题】:How to follow Uncle Bob's rule(recommendation) to use one try-catch block in one method correctly?如何遵循 Bob 叔叔的规则(推荐)在一种方法中正确使用一个 try-catch 块?
【发布时间】:2022-04-26 13:12:56
【问题描述】:

例如,我有一个方法

void process(String userId) {
  if(userId == null) throw new IlligalArgumentException(\"Usesr ID is required);

  User user = userService.findUserById(userId);

  if(user == null) throw new UserNotFoundException(\"User with ID: \"+ userId +\" not found\");
  
  try {
     DataResponse response = analyticsAPI.loadAnalytics(userId, user.getDob(), user.getFirstName());  

     //logic
   } catch(AnalyticsAPIException e) {
     //logic
   }
 }
  1. IlligalArgumentException未经检查例外
  2. UserNotFoundException未经检查例外
  3. AnalyticsAPIException检查例外

    我读到最好的做法是从 try 开始方法并以 catch 结束,而不是在一个方法中将 try-catch 块相乘。

    首选异常而不是错误代码 我们更喜欢异常而不是错误代码 因为它们更明确。在处理 try/catch 时,我们 不应在函数中添加比 try / catch 块更多的逻辑,所以 该函数只做一件事:处理错误。建议:不要使用 嵌套尝试/捕获。

    像这样的东西:

    void process(String userId) {
      try {
          if(userId == null) throw new IlligalArgumentException(\"Usesr ID is required);
        
          User user = userService.findUserById(userId);
        
          if(user == null) throw new UserNotFoundException(\"User with ID: \"+ userId +\" not found\");
          
             DataResponse response = analyticsAPI.loadAnalytics(userId, user.getDob(), user.getFirstName());  
    
             //logic
           } catch(AnalyticsAPIException e) {
             //logic
           }
         }
    

    但它看起来很奇怪。我在 try-catch 块内抛出异常,并希望它不会在 catch 中处理。我希望它将被抛出到调用该方法的服务之上。

    接下来我可以做:

    public void process(String userId) {
              try {
                  if(userId == null) throw new IlligalArgumentException(\"Usesr ID is required);
                
                  User user = userService.findUserById(userId);
                
                  if(user == null) throw new UserNotFoundException(\"User with ID: \"+ userId +\" not found\");
                  
                  DataResponse response = callApi(userId, user.getDob(), user.getFirstName());  
            
                  //logic
                 }
        
    private DataResponse callApi(String userId, Date dob, String firstName){
                   try {
                     return analyticsAPI.loadAnalytics(userId, user.getDob(), user.getFirstName());  
                   } catch(AnalyticsAPIException e) {
                     //logic
                   }
             }
    

    但它并不总是有效。那么,什么是更好的呢?

  • 我相信最佳实践是推荐像您的第二个提案这样的代码。如果您不能使用第二个提议,那么您需要嵌套的 try-catch 块,并且没有真正的解决方法。
  • 如果您想向调用者重新抛出某些类型的异常,您可以捕获最通用的Exception e,并在catch 块中使用instanceof 来检查刚刚捕获的异常的实际类型。然后,只需发出 throw e 如果它是您要重新抛出的异常类型。

标签: java exception architecture refactoring clean-architecture


【解决方案1】:

unclebob 的建议是,在 try 或 catch 块中没有语句列表。相反,您应该将“正常”情况与异常情况分开。目标是分离不同的抽象级别。

为避免名称冲突,我经常在“正常”大小写前加上“尝试”字样。 我也经常用自己的方法将 try/catch 分开以保持重点。例如。

“处理”方法应该关注“处理用户(userId)”的含义。它是一个抽象级别,如果将其与其他方法分开,则更易于阅读和理解。

void process(String userId) {
    User user = getUserById(userId);

    loadAnalytics(user);
}

getUserById 仅关注您想要通过其 id 获取用户时所需的逻辑。

void void getUserById(String userId){
    if(userId == null) throw new IlligalArgumentException("Usesr ID is required");
    
    User user = userService.findUserById(userId);
    if(user == null) throw new UserNotFoundException("User with ID: "+ userId +" not found");
    
    return user;
}

要了解“过程”方法,无需了解 加载分析可能会导致异常状态,甚至是它们的处理方式。

但是,当您深入研究 loadAnalytics 方法时,您想知道它是如何工作的。现在您可以立即看到加载分析可能会导致异常状态。该方法专注于异常处理,因为它只包含 try/catch 并且您还关注可能发生的异常类型。

void loadAnalytics(User user){
    try {
     tryLoadAnalytics(user);
    } catch(AnalyticsAPIException e) {
     handleAnalyticsError(e);
    }
}

我经常使用“try”前缀来避免名称冲突并明确方法可能会失败。

void tryLoadAnalytics(){
    DataResponse response = callApi(userId, user.getDob(), user.getFirstName());  
    
    //logic
}

与“正常”情况一样,异常处理是分开的,因此您可以专注于如何处理特定异常。

void handleAnalyticsError(AnalyticsAPIException e){
    //logic
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-03
    • 2015-07-04
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 1970-01-01
    相关资源
    最近更新 更多