Java 限制变量范围的命名块:好主意?

Java 限制变量范围的命名块:好主意?,java,coding-style,Java,Coding Style,多年来,我一直使用命名块来限制临时变量的范围。我从来没有在其他地方见过这样做,这让我怀疑这是否是个坏主意。特别是由于EclipseIDE默认将这些标记为警告 我想,在我自己的代码中,我已经很好地使用了它。但是,由于它不习惯使用,以至于优秀的程序员在看到它时会不信任它,因此我有两条路要走: 避免这样做,或者 推广它,希望它能成为一种习语 示例(在较大的方法中): 在这里,我使用GregorianCalendar只是初始化一个日期,我想确保不会意外地重用它 有些人评论说,您实际上不需要为块命名。虽然

多年来,我一直使用命名块来限制临时变量的范围。我从来没有在其他地方见过这样做,这让我怀疑这是否是个坏主意。特别是由于EclipseIDE默认将这些标记为警告

我想,在我自己的代码中,我已经很好地使用了它。但是,由于它不习惯使用,以至于优秀的程序员在看到它时会不信任它,因此我有两条路要走:

  • 避免这样做,或者
  • 推广它,希望它能成为一种习语
  • 示例(在较大的方法中):

    在这里,我使用GregorianCalendar只是初始化一个日期,我想确保不会意外地重用它

    有些人评论说,您实际上不需要为块命名。虽然这是真的,但一个原始块看起来更像一个bug,因为它的意图还不清楚。此外,命名某物会鼓励您思考块的意图。这里的目标是识别代码的不同部分,而不是为每个临时变量指定自己的范围

    许多人评论说,最好直接使用小方法。我同意这应该是你的第一本能。然而,可能有几个缓解因素:

      <> LI>即使考虑命名块,代码应该是短的、一次性的代码,它永远不会被调用到别处。
    • 命名块是一种快速组织超大方法的方法,无需创建包含十几个参数的一次性方法。当一个类处于不断变化中,并且输入可能会随着版本的变化而变化时,这一点尤其正确
    • 创建一个新方法会鼓励其重用,如果用例没有很好地建立起来,这可能是不明智的。命名块更容易(至少在心理上)丢弃
    • 特别是对于单元测试,您可能需要为一次性断言定义十几个不同的对象,而它们的不同程度足以让您(还)无法找到将它们合并到少量方法中的方法,也无法想出用不长的名称来区分它们的方法
    使用命名作用域的优点:

  • 不能意外地重用临时变量
  • 有限范围为垃圾收集器和JIT编译器提供了有关程序员意图的更多信息
  • 块名提供了一个关于代码块的注释,我发现它比开放式注释更具可读性
  • 使将代码从大方法重构为小方法变得更容易,反之亦然,因为命名块比非结构化代码更容易分离
  • 缺点:

    不惯用:没有见过命名块的这种用法的程序员(即除了我以外的所有人)认为这是错误的,因为他们找不到块名的引用。(就像Eclipse一样。)要让某些东西变得地道是一场艰苦的战斗

    它可以作为不良编程习惯的借口,例如:

    • 制作巨大的整体方法,其中几个小方法更清晰
    • 压痕的层次太深,不容易阅读

    注:根据一些深思熟虑的回答,我对这个问题进行了广泛的编辑。谢谢

    我会直接去重构成更小的方法。如果一个方法足够大,需要像这样分解,那么如果可能的话,它确实需要分解成多个方法


    虽然限制范围很好,但这并不是命名块的真正用途。它是单向的,这很少是一件好事。

    如果有5-10行代码可以安全地放入这样的块中,那么同样的代码也可以被提取到方法中


    这似乎只是语义上的差异,但至少通过提取到一个方法中,您将获得重用能力的好处。

    如果这不好,那么为什么这是语言中的一个功能!这是有目的的,你已经找到了

    我经常编写与您的示例完全相同的代码。当你想初始化一个变量时,需要做一些计算来确定它应该是什么,这涉及到几个变量。。。然后,您不希望这些变量在整个函数范围内都存在,那么一个包含初始化的小范围就很好了

    迷你作用域是将代码分解为“段落”的简单方法。如果将这些方法拆分为多个方法,那么当这些方法没有从其他地方被调用,并且它们的执行顺序是串行的时,代码就更难导航了

    这始终是一种平衡,但如果您认为它将是最容易维护的,并且如果它都是内联的,它实际上会为将来的代码读者增加价值,那么就去做吧


    没有硬性规定。有时我对同事们有点厌烦,他们过分地将所有内容都放在自己的方法、类或文件中,这就成了一场噩梦。某处有一个很好的平衡

    我在我的一些c#中这样做过。我不知道你能说出这些块的名字,我得试试看它在c#中是否也能用

    我认为范围块是个不错的主意,因为您可以将特定于某个代码块的代码封装在一个代码块中,而您可能不希望将其拆分为自己的函数


    至于嵌套它们的缺点,我认为这更多是程序员的错误,而不是作用域块本身的错误

    在我的书中,使用块来限制范围是一种很好的技巧


    但是,既然您使用标签来处理注释,为什么不直接使用实际的注释呢?这将消除关于未引用标签的混淆。

    有时我使用未命名的块来隔离准备一些不可变的东西所需的可变的东西。我没有使用标签,而是将块放在不可变变量声明下

    final String example;
    {
       final StringBuilder sb = new StringBuilder();
       for(int i = 0; i < 100; i++)
         sb.append(i);
       example = sb.toString();
    
    }
    
    最后一个字符串示例;
    {
    终纹
    
    final String example;
    {
       final StringBuilder sb = new StringBuilder();
       for(int i = 0; i < 100; i++)
         sb.append(i);
       example = sb.toString();
    
    }
    
    final Date nextTuesday;
    initNextTuesday: {
        GregorianCalendar cal = new GregorianCalendar();
        ... // About 5-10 lines of setting the calendar fields
        nextTuesday = cal.getTime();
    }
    
    final Date nextTuesday;
    initNextTuesday: {
        GregorianCalendar cal = new GregorianCalendar();
        //1
        //2
        //3
        //4
        //5
        nextTuesday = cal.getTime();
    }
    
    final Date nextTuesday = getNextTuesday();
    
    Type foo(args..){
        declare ret
        ...
        make temp vars to add information on ret
        ...
    
        make some more temp vars to add info on ret. not much related to above code. but previously declared vars are still alive
        ...
    
    
        return ret
    }
    
    class Break {
        public static void main(String args[]) {
            boolean t = true;
            first: {
                second: {
                    third: {
                        System.out.println("Before the break.");
                        if (t)
                            break second; // break out of second block
                        System.out.println("This won't execute");
                    }
                    System.out.println("This won't execute");
                }
                System.out.println("This is after second block.");
            }
        }
    }
    
    class BreakLoop4 {
        public static void main(String args[]) {
            outer: for (int i = 0; i < 3; i++) {
                System.out.print("Pass " + i + ": ");
                for (int j = 0; j < 100; j++) {
                    if (j == 10)
                        break outer; // exit both loops
                    System.out.print(j + " ");
                }
                System.out.println("This will not print");
            }
            System.out.println("Loops complete.");
        }
    }