你如何在Java中以更好的方式编写这些循环?

时间:2009-10-30 23:35:50

标签: java refactoring loops

我有一组对象,我想按照它们被迭代的顺序进行一些操作。在该操作被调用之后,我想对它们执行其他操作。基本上,代码看起来像这样:

for(int i = 0;i < myobj.size();i++)
{
   myobj.at(i).doSomething();
}

for(int i = 0;i < myobj.size();i++)
{
   myobj.at(i).doSomethingElse();
}

这对我来说看起来很难看。我怎么能把它重写成更好的东西?操作的顺序应该保持不变。

10 个答案:

答案 0 :(得分:24)

我不知道myobj是什么,但如果它是Iterable,那么你可以使用foreach循环:

for (Foo foo : myobj) {
  foo.doSomething();
}

for (Foo foo : myobj) {
  foo.doSomethingElse();
}

如果它不是Iterable,那么这样做也可能有助于其他代码。

答案 1 :(得分:6)

如果绝对必须在不同的循环中进行这两个操作,请将循环重构为适当命名的方法,以便一目了然更容易理解:

createData();
saveData();

答案 2 :(得分:4)

使用foreach循环:

for (MyObject currentObject : myobj) {
  currentObject.doSomething();
}

for (MyObject currentObject : myobj) {
  currentObject.doSomethingElse();
}

答案 3 :(得分:3)

这看起来是您应用Visitor pattern的绝佳机会。

答案 4 :(得分:3)

答案 5 :(得分:2)

通过使用lambdaj,您可以获得相同的结果,而无需编写任何显式循环:

forEach(myobj).doSomething();
forEach(myobj).doSomethingElse();

答案 6 :(得分:1)

与其他产品略有不同:让您对方法的调用返回下一个要操作的项目,并使用明确定义的终止返回(例如,null):

while ((holder = holder.doSomething())!=null);
while ((holder = holder.doSomethingElse())!=null);

显然,有一些初步和干预重新分配持有人。赞成访客建议,实现Iterable也是一个不错的选择;我的解决方案也可以被视为使用myObj实现Iterator:

while (myObj.hasNext()) myObj.next().doSomething();
myObj.resetIterator();
while (myObj.hasNext()) myObj.next().doSomethingElse();

一个缺点是,如果你达到了doSomething()和doSomethingElse()可以在一个循环中应用的点,而不是两个独立的循环,你必须有一个合并的方法来使这个工作并利用那种变化。

for-loop上的替代方案,使用后修复(实际上受到那种可怕的混淆解决方案的启发):

int size = myObj.size(), i=0;
while (i<size) myObj.at(i++).doSomething();
i=0;
while (i<size) myObj.at(i++).doSomethingElse();

并且,如果只有doSomething()on all和doSomethingElse()的所有事项的顺序(即,不是访问它们的索引顺序),你甚至可以跳过中间的重新分配,并且只是预先修复第二次调用的减量。

int size = myObj.size(), i=0;
while (i<size) myObj.at(i++).doSomething();
while (i>0) myObj.at(--i).doSomethingElse();

当然,如果myObj实现了ListIterator而不是Iterator,那么上面的Iterator解决方案的版本更加性感(好吧,我现在停止编辑更多的东西......认真)。

答案 7 :(得分:0)

你可以像

一样做同样丑陋的事情
bool d=false;
for(int i = 0;i < myobj.size();i++)
{
   if(d==false){
     myobj.at(i).doSomething();
   }else{
     myobj.at(i).doSomethingElse();
   }
   if(i==myobj.size()-1 && d==false){ d=true; i=0;}
}

答案 8 :(得分:0)

这是另一种写作方式。

我认为,这是访客模式,虽然我一直看到它但我不太明白(访客文档)所以,这可能是其他的。

无论如何,我们的想法是使用匿名内部类(假Java “闭包”)并编写迭代一次。

public class IterationSample {
    public static void main( String [] args ) {

        Foo [] items = new Foo[0]; // get it from somewhere  ....

        iterate( items , new _(){void with( Foo f ){
            f.doSomething();
        }});    

        iterate( items , new _(){void with( Foo f ){
            f.doSomethingElse();
        }});    

        iterate( items , new _(){void with( Foo f ){
            f.doBar();
        }});   



    }
    // write  the loop once.
    static void iterate( Foo [] items, _ visitor ) {
        for( Foo f : items ) {
            visitor.with( f );
        }
    }
}

Foo对象将是对象。

// Not really abstract just for the sake of the sample. Use your own.
abstract class Foo {
    abstract void doSomething();
    abstract void doSomethingElse();
    abstract void doBar();

}

最后这是“访客”

// made abstract instead of interface just to avoid having to type 
// "public" each time. 
abstract class  _ {
    abstract void with( Foo f );
}

遗憾的是我无法避免该方法的返回类型。

否则这个

         iterate( items ,new _(){ with( Foo f ){ 

读作:

  

使用foo

迭代项目“noise”

为什么你可以做this

因为这样你可以有一系列的操作:

 _ [] operations = {
        new _(){void with( Foo f ){
            f.doSomething();
        }},
        new _(){void with( Foo f ){
            f.doSomethingElse();
        }},
        new _(){void with( Foo f ){
            f.doBar();
        }}
 };

并迭代它们:)

  for( _ andPerformAction : operations ) {
      iterate( items , andPerformAction );
  }

可能有一些情况,虽然我现在可以想到= -S

答案 9 :(得分:-3)

嗯,这对你有用吗?

for(int i = 0;i < myobj.size();i++)
{   
    myobj.at(i).doSomething();
    myobj.at(i).doSomethingElse();
}