哪个更好?在每个其他函数定义的末尾使用while循环或调用main函数

时间:2014-02-05 08:27:48

标签: java while-loop

MainScreen() {
    DisplayUI();
    GetInput();
}
DisplayUI {
    // prints press 1 for this 2 for that etc...
}
GetInput() {
    // Gets input and calls the next approprite function according to that input e.g 1 for login etc...
    // e.g 
    if (input == 1) {
    Login();
    }
    .
    .
    .
    if (input == x) {
    somefunc();
    }
    // if the user enters an input that is not accounted for call this function
    MainScreen();
}

Login() {
    // do some stuff
    MainScreen();
}
somefunc() {
    // do some stuff
    MainScreen();
}

main {
    MainScreen();
}

使用上述方法是否有任何缺点(使用MainScreen();在每个函数实现结束时?)?

对此(使用while循环并从每个函数的末尾删除MainScreen())

哪一个更好?在任何一种情况下,我都想无限期地运行我的程序。我使用了上面的方法,我的程序运行完美,是否需要更改我的代码?

main {
    while(true){
        MainScreen();   // 
    }
}

3 个答案:

答案 0 :(得分:3)

使用循环肯定更好。

在每个函数的末尾加上MainScreen();会违反DRY原则(例如,如果您决定更改该函数名,则必须找到放置该语句的所有位置)。

此外,不需要递归,所以不要使用它。

答案 1 :(得分:2)

递归方法将导致一个非常大的调用堆栈,并且不可避免地导致StackOverflow

因此我建议while循环。

答案 2 :(得分:0)

调用函数时,程序必须知道在完成函数后继续执行的位置。让我们用一个简单的伪代码程序来说明这一点:

function HelloWorld() {
    print "Hello, World!\n";
}

function Main() {
    print "1... "; HelloWorld();
    print "2... "; HelloWorld();
    print "3... "; HelloWorld();
}

Main();
print "Good bye.\n";

这个程序的输出将是相当简单的

1... Hello, World!
2... Hello, World!
3... Hello, World!
Good bye.

换句话说,程序调用Main()。

Main反过来打印“1 ...”,调用HelloWorld,然后继续执行,打印“2 ...”,cals HelloWorld,然后继续执行,打印“3 ...”,调用HelloWorld作为最终版本时间,继续执行,所以退出。

此时,程序在调用Main后继续执行,因此打印告别然后退出。

换句话说,对于您调用的每个函数,您的程序必须记住在调用函数中的继续位置。它通过维护名为调用堆栈的内容来实现。

无论何时调用函数,都会在该调用堆栈的顶部推送调用框架。该调用帧包含下一个要执行的指令的存储器地址以及函数调用时范围内的变量值。当函数退出时,最顶层的调用框将从callstack中弹出。程序跳转到存储在该帧中的内存地址,并愉快地继续关注其业务。

所以你调用的每个函数的调用堆栈增长缩小,每个函数都会完成更改。

在我们上面的小程序中,堆栈永远不会包含超过三帧(这是一个荒谬的小数量):

  1. 最初,调用帧为空。 (堆栈大小= 0)
  2. 我们调用Main() - 推送一个框架(堆栈大小= 1)
    1. 我们呼叫print - 推送一个框架(堆栈大小= 2)
    2. print退出 - 弹出一个框架(堆栈大小= 1)
    3. 重复步骤2.1和2.2两次。
  3. Main()退出 - 弹出一个框架(堆栈大小= 0)
  4. 程序退出(堆栈大小= 0)
  5. 现在让我们看看如果我们重写这样的程序会发生什么:

    function HelloWorld() {
        print "Hello, World\n";
    }
    
    function Main () {
        while (true) {
            HelloWorld();
        }
    }
    
    Main();
    

    这会创建一个调用HelloWorld的无限循环,我们将在宇宙结束之前(或者用户按下Ctrl + C或断电)问候世界。

    调用堆栈会发生什么?

    1. 开始计划。 (堆栈大小= 0)
    2. 调用Main() - 推送一个框架(堆栈大小= 1)
    3. 调用HelloWorld() - 推送一个框架(堆栈大小= 2)
    4. HelloWorld()退出 - 弹出一个框架(堆栈大小= 1)
    5. 返回第3步并从那里继续。
    6. 调用堆栈在具有1到2帧之间交替,考虑到程序永远不会结束,这是非常合理的。

      现在,我们不是使用while循环,而是在Main()结束时调用HelloWorld()

      function HelloWorld() {
          print "Hello, World!\n";
          Main();
      }
      
      function Main() {
          HelloWorld();
      }
      
      Main();
      

      从表面上看,这会产生相同的无限循环,我们会向世界打印问候语,直到天结束。但在引擎盖下发生了不同的事情。你能看到吗?

      1. 开始程序(堆栈大小= 0)
      2. 调用Main() - 按一帧(堆栈大小= 1)
      3. 调用HelloWorld() - 推送一个框架(堆栈大小= 2)
      4. 调用Main() - 按一帧(堆栈大小= 3)
      5. 调用HelloWOrld() - 推送一个帧(堆栈大小= 4)。
      6. ......我相信你会得到这种模式。

        最终你的程序会崩溃,大声抱怨堆栈溢出。