16

我正在考虑使用匿名{ }代码块在同一方法调用中逻辑区分“代码块”的选项,这(理论上)应该提高代码的可读性。

我想知道以下 2 个代码段中哪一个更适合您?

另外,这两个代码段是否编译为相同的字节码?换句话说,使用{ }会以任何方式损害代码的性能吗?

选项 1:没有 { } 标识的代码块

 public static String serviceMatch(HttpServletRequest servletRequest, RequestTypeEnum requestTypeEnum, ...censorsed..., RequestStatistics requestStatistics) {
  Request request;

  // We get the parser that fits the ...censorsed..., effectively transforming the HTTPReqeuest to application local "Request*" object
  RequestParser parser = RequestParserFactory.getParser(...censorsed...);

  // Populate basic parameters, the "heavy" data will be lazy loaded
  request = parser.parse(servletRequest);

  // Instead of polluting the parsers let's put it here... (unless we identify meaningful justifications for the other alternative of changing RequestParser.parse() interface.
  request.requestType = requestTypeEnum;

  // Store the request statistics object on the request, so that we have access to it from all over the code
  request.requestStatistics = requestStatistics;



  // Update timestamp when request was parsed
  request.requestStatistics._1_end_parseRequest = System.currentTimeMillis();


  /*
   * ...censorsed...
   */
  MatchResult matchResult = Matcher.findMatch(...censorsed...);

  /*
   * ...censorsed...
   */
  String reply = ReplyFormatFactory.getFormatter(...censorsed...

  // Update timestamp when reply finished construction
  request.requestStatistics._6_end_formatReply = System.currentTimeMillis();

  return reply;
 }

选项 2:带有 { } 标识的代码块

 public static String serviceMatch(HttpServletRequest servletRequest, RequestTypeEnum requestTypeEnum, ...censorsed..., RequestStatistics requestStatistics) {
  Request request;

  /*
   * Request parsing block
   */
  {
   // We get the parser that fits the ...censorsed..., effectively transforming the HTTPReqeuest to application local "Request*" object
   RequestParser parser = RequestParserFactory.getParser(...censorsed...);

   // Populate basic parameters, the "heavy" data will be lazy loaded
   request = parser.parse(servletRequest);

   // Instead of polluting the parsers let's put it here... (unless we identify meaningful justifications for the other alternative of changing RequestParser.parse() interface.
   request.requestType = requestTypeEnum;

       // Store the request statistics object on the request, so that we have access to it from all over the code
   request.requestStatistics = requestStatistics;
  }



  // Update timestamp when request was parsed
  request.requestStatistics._1_end_parseRequest = System.currentTimeMillis();


  /*
   * ...censorsed...
   */
  MatchResult matchResult = Matcher.findMatch(...censorsed...);

  /*
   * ...censorsed...
   */
  String reply = ReplyFormatFactory.getFormatter(...censorsed...

  // Update timestamp when reply finished construction
  request.requestStatistics._6_end_formatReply = System.currentTimeMillis();

  return reply;
 }

感谢您的评论,马克西姆。

4

10 回答 10

55

如果您{ }只是为了可读性而考虑在同一方法中添加额外的 's,我的建议是考虑将您的方法重构为几个较小的方法。
这些较小的方法的优点是它们本身更容易理解,并且更可重用(如果它们是“松散耦合的”)。参见单一责任原则

于 2010-10-25T17:31:58.653 回答
13

如果您发现将括号放在代码的某些部分周围会很方便(如在选项 2 中),您应该将其移动到自己的方法中。这就是提高可读性的原因。

顺便说一句,我也认为您实际上不需要注释代码的每一行。例如,即使没有注释,时间戳更新也是不言自明的。

于 2010-10-25T17:32:49.327 回答
3

我通常不会在没有某种语法原因的情况下添加大括号分隔的块,但如果仅在有限范围内需要变量,我宁愿创建一个嵌套范围而不是在更大的中间定义变量(因为在后一种情况下,当变量超出“有用”范围时,没有明确的指示)。

至于将这样的代码块提取到另一个方法中,我认为如果生成的方法(1)具有合理的参数批次,并且(2)可以给出描述其行为的名称以及实际代码可以。如果使用该方法需要传递过多的参数,或者如果必须查看方法中的代码以了解其调用者在做什么,那么我认为最好使用匿名范围块。

于 2010-10-25T18:17:19.027 回答
1

我认为这有点主观,没有正确或错误的答案……我的意见是不要这样做。用注释块分隔代码块并解释它们为什么不同,但不要使用大括号。当我看到大括号时,我立即认为应该有一个前导if, while, 或其他东西......而没有找到 is 有点奇怪。

于 2010-10-25T17:32:51.697 回答
1

您可能应该使用单独的方法。你可以调用第一个块processRequest。任何阅读此代码的人都将能够看到使用了哪些参数、返回了哪些数据、它做了什么(即使没有注释)。块不提供此类信息。

字节码可能是相同的。

于 2010-10-25T17:34:41.217 回答
0

大括号有其用途(在Java 7{ }中更是如此),我认为它们很少仅用于可读性。就个人而言,如果它们像在选项 2 中那样使用,我首先想到的是,“这是一个静态块吗?”。因此,我发现选项 1“更正常”且可读性强。

如果您真的热衷于坚持使用一种方法而不是像这里许多人建议的那样重构这段代码,那么请使用注释作为行分隔符。就像是:

    /* -------------------------------------------- */
    /* describe in detail here why you don't want to put this in another method */
    /* so other readers will know why! */

   // We get the parser that fits the ...censorsed..., effectively transforming the HTTPReqeuest to application local "Request*" object
   RequestParser parser = RequestParserFactory.getParser(...censorsed...);

   // Populate basic parameters, the "heavy" data will be lazy loaded
   request = parser.parse(servletRequest);

   // Instead of polluting the parsers let's put it here... (unless we identify meaningful justifications for the other alternative of changing RequestParser.parse() interface.
   request.requestType = requestTypeEnum;

       // Store the request statistics object on the request, so that we have access to it from all over the code
   request.requestStatistics = requestStatistics;
  }
   /* -------- END of confusing block ------------- */

恕我直言,注释可能是使代码可读的最佳方法。

于 2010-10-26T10:48:24.820 回答
0

大括号通常用于对控制结构等的语句进行分组。当用于其他任何事情时,我发现它们很刺耳。

如果我有一个过长的函数(无论出于何种原因)我不想拆分,我会将它分成带有注释的块。

于 2010-10-25T21:12:12.100 回答
0

Lighttpd 在配置文件中有一个注释块,以这种风格制作;

#{{{ module name
module.option = value;
module.option = value;
#}}} 

因此,您可以只评论而不是 {}'ing 您的代码。

在 Perl 中,将评估 { }、sub { } 或 eval { } 内的任何内容;然而,在某个子例程中保留大量 { } 块被认为足以将代码分成较小的部分推出;

$html .= 评估 { $val = &getNextPiece(); 返回 $val; };

所以这种做法是众所周知的。

于 2010-10-25T20:59:57.063 回答
0

如果您使用 C# 进行开发,我建议您使用 #region ... #endregion 代替以提高可读性。

于 2010-10-25T17:35:43.737 回答
0

有时更喜欢使用第二个选项。当提取单独的方法会导致多个返回参数混乱(即,将它们包装在人造对象中)时,就会发生这种情况。

于 2010-10-25T17:37:03.833 回答