重构标记的循环

时间:2008-08-19 07:42:02

标签: java refactoring label

在我确信已标记的中断/继续是here之后的“nono”时,我需要帮助才能删除代码中的标签。

我有一个方阵和一个长度相同的矢量。向量中已经有一些值,取决于矩阵中的值,循环中的向量发生了变化。

我希望,代码片段基本上是可以理解的......

vectorLoop:
for( int idx = 0; idx < vectorLength; idx++) {
    if( conditionAtVectorPosition( v, idx ) ) continue vectorLoop;

    matrixLoop:
    for( rowIdx = 0; rowIdx < n; rowIdx++ ) {
        if( anotherConditionAtVector( v, rowIdx ) ) continue matrixLoop;
        if( conditionAtMatrixRowCol( m, rowIdx, idx ) ) continue vectorLoop;
    }
    setValueInVector( v, idx );
}     

请说服我,没有标签的版本更具可读性/更好。

12 个答案:

答案 0 :(得分:34)

看看到目前为止提出的解决方案:

  • 它们看起来都不如原作,因为它们涉及在代码机制上花费更多代码而不是算法本身

  • 其中一些已被破坏,或者在编辑之前。最让人沮丧的是,人们不得不非常认真地思考如何在没有标签的情况下编写代码,而不是破坏任何东西。

  • 有些人会因为两次运行相同的测试而受到性能损失,这可能并非总是微不足道。另一种方法是存储和传递圆形布尔值,这很难看。

  • 将代码的相关部分重构为方法实际上是一种无操作:它重新排列代码在文件中的布局方式,但对其执行方式没有影响。

所有这些让我相信,至少在这个问题的情况下,标签是正确的解决方案,不需要重构。当然,有些情况下标签使用不当,应该重构。我不认为它应该被视为一些牢不可破的规则。

答案 1 :(得分:1)

很容易,我的好人。

for( int idx = 0; idx < vectorLength; idx++) {
  if( conditionAtVectorPosition( v, idx ) ) continue;

  for( rowIdx = 0; rowIdx < n; rowIdx++ ) {
    if( anotherConditionAtVector( v, rowIdx ) ) continue;
    if( conditionAtMatrixRowCol( m, rowIdx, idx ) ) break;
  }
  if( !conditionAtMatrixRowCol( m, rowIdx, idx ) )
    setValueInVector( v, idx );
}
编辑:很正确你是安德斯。我已经编辑了我的解决方案,也考虑到了这一点。

答案 2 :(得分:1)

@Patrick你假设调用setValueInVector(v,idx);在第二个循环结束时没问题。如果代码在逻辑上相同,则必须将其重写为如下所示:

for( int idx = 0; idx 

答案 3 :(得分:1)

阅读您的代码。

  • 我注意到你在conditionAtVectorPosition消除了无效的向量位置,然后你在anotherConditionAtVector上删除了无效的行。
  • 似乎检查anotherConditionAtVector的行是多余的,因为无论idx的值是什么,anotherConditionAtVector只依赖于行索引(假设anotherConditionAtVector没有副作用)。

所以你可以这样做:

  • 首先使用conditionAtVectorPosition获取有效位置(这些是有效列)。
  • 然后使用anotherConditionAtVector获取有效行。
  • 最后,使用conditionAtMatrixRowCol使用有效的列和行。

我希望这会有所帮助。

答案 4 :(得分:1)

@ Nicolas

  
    

其中一些已被破坏,或者在编辑之前。最诅咒的事实是     人们不得不考虑如何编写没有标签的代码,而不是     打破任何事情。

  
     

我有一个不同的观点:其中一些被打破,因为很难弄明白   原算法的行为。

我意识到这是主观的,但我在阅读原始算法时没有任何问题。它比建议的替代品更短更清晰。

此线程中的所有重构都使用其他语言功能模拟标签的行为 - 就好像您将代码移植到没有标签的语言一样。

答案 5 :(得分:1)

有些人会因为两次运行相同的测试而受到性能损失,这可能并不总是微不足道。另一种方法是存储和传递圆形布尔值,这会变得丑陋。
性能损失很小。但是我同意两次运行测试不是一个好的解决方案。

我认为问题是如何删除标签,而不是如何优化算法。在我看来,原始海报不知道如何在没有标签的情况下使用“继续”和“破解”关键字,但当然,我的假设可能是错误的。

在性能方面,帖子没有提供有关其他功能实现的任何信息,所以我知道他们也可以通过FTP下载结果,包括编译器内联的简单计算。 / p>

话虽如此,在理论上做两次相同的测试并不是最佳的。

编辑:再想一想,这个例子实际上并不是标签的可怕使用。我同意"goto is a no-no",但不是因为这样的代码。这里使用标签实际上并不会显着影响代码的可读性。当然,它们不是必需的,可以很容易地省略,但不能简单地使用它们,因为“使用标签是坏的”在这种情况下不是一个好的论据。毕竟,删除标签不会使代码更容易阅读,因为其他人已经评论过。

答案 6 :(得分:1)

这个问题不是关于优化算法 - 但无论如何,谢谢;-)

在我写这篇文章时,我认为标记为“继续”是一种可读的解决方案。

我问过question关于Java中标签的约定(标签是否全部大写)。

基本上每个答案都告诉我“不要使用它们 - 总有一种更好的方法!重构!”。所以我发布了这个问题,要求提供更具可读性(因此更好?)的解决方案。

到目前为止,我并不完全相信目前提供的替代方案。

请不要误会我的意思。标签在大多数时候都是邪恶的。

但在我的情况下,条件测试非常简单,算法取自数学论文,因此很可能在不久的将来不会改变。所以我更喜欢一次看到所有相关部分,而不必滚动到另一个名为checkMatrixAtRow(x)的方法。

特别是在更复杂的数学算法中,我发现很难找到“好”的函数名称 - 但我想这是另一个问题

答案 7 :(得分:1)

我认为标记的循环非常罕见,你可以选择任何标记方法为你工作 - 你所拥有的东西使你的意图继续完全清楚。


在主要建议重构原始问题中的循环并现在看到有问题的代码后,我认为你有一个非常易读的循环。

我想象的是一个非常不同的代码块 - 把实际的例子放好,我可以看到它比我想象的要清晰得多。

我为误会道歉。

答案 8 :(得分:0)

这对你有用吗?我将内部循环解压缩为一个方法CheckedEntireMatrix(你可以比我更好地命名) - 而且我的java有点生疏......但我认为它得到了消息

for( int idx = 0; idx < vectorLength; idx++) {
    if( conditionAtVectorPosition( v, idx ) 
    || !CheckedEntireMatrix(v)) continue;

    setValueInVector( v, idx );
}

private bool CheckedEntireMatrix(Vector v)
{
    for( rowIdx = 0; rowIdx < n; rowIdx++ ) {
        if( anotherConditionAtVector( v, rowIdx ) ) continue;
        if( conditionAtMatrixRowCol( m, rowIdx, idx ) ) return false;
    }   
    return true;
}

答案 9 :(得分:0)

Gishu有正确的想法:

for( int idx = 0; idx < vectorLength; idx++) {
    if (!conditionAtVectorPosition( v, idx ) 
        && checkedRow(v, idx))
         setValueInVector( v, idx );
}

private boolean checkedRow(Vector v, int idx) {
    for( rowIdx = 0; rowIdx < n; rowIdx++ ) {
        if( anotherConditionAtVector( v, rowIdx ) ) continue;
        if( conditionAtMatrixRowCol( m, rowIdx, idx ) ) return false;
    }  
    return true;
}

答案 10 :(得分:0)

我不太清楚第一次继续理解。 我会复制Gishu并写下类似的内容(抱歉,如果有一些错误):

for( int idx = 0; idx < vectorLength; idx++) {
    if( !conditionAtVectorPosition( v, idx ) && CheckedEntireMatrix(v))
        setValueInVector( v, idx );
}

inline bool CheckedEntireMatrix(Vector v) {
    for(rowIdx = 0; rowIdx < n; rowIdx++)
        if ( !anotherConditionAtVector(v,rowIdx) && conditionAtMatrixRowCol(m,rowIdx,idx) ) 
            return false;
    return true;
}

答案 11 :(得分:0)

@ Sadie

  

它们看起来都比原来的可读性差,因为它们涉及在代码机制上花费更多代码而不是算法本身

在算法之外外化第二个循环的可读性不一定。如果方法名称选择得当,可以提高可读性。

  

其中一些已被破坏,或者在编辑之前。最令人沮丧的是,人们不得不非常认真地思考如何在没有标签的情况下编写代码,而不是破坏任何东西。

我有一个不同的观点:其中一些被打破,因为很难弄清楚原始算法的行为。

  

有些人会因为两次运行相同的测试而受到性能损失,这可能并不总是微不足道。另一种方法是存储和传递圆形布尔值,这很难看。

性能损失很小。但是我同意两次运行测试不是一个好的解决方案。

  

将代码的相关部分重构为方法实际上是一种无操作:它重新排列代码在文件中的布局方式,但不会影响它的执行方式。

我没有看到这一点。是的,它不会改变行为,比如......重构?

  

当然,有些情况下标签使用不当,应该重构。我不认为它应该被视为一些牢不可破的规则。

我完全同意。但正如你所指出的那样,我们中的一些人在重构这个例子时遇到了困难。即使最初的例子是可读的,也很难维护。