在 Java for 循环中插入额外代码

Posted

技术标签:

【中文标题】在 Java for 循环中插入额外代码【英文标题】:Inserting extra code into Java for loops 【发布时间】:2014-03-14 14:08:32 【问题描述】:

我有一批精灵(带纹理的 OpenGL ES 2.0 Quads),我循环移动它们。这是我的代码的简化版本:

//'sprite' & other values have been are assumed to exist for the purpose of the question

public void moveQuadBatch()

    //Loop for as many sprites as there are to draw
    for (loop = 0; loop < sprite.number; loop++)

        moveQuadNumber(loop); //this method will move the sprite that corresponds to the number loops so we can move through the entire batch and move each individual sprite


    

现在,对于某些批次,有一个倒数计时器或其他一些条件(而对于其他批次则没有,如上)。因此,我为这些对象创建了一个类似的方法,如下所示:

public void moveQuadBatchWithCheck()

    //Loop for as many sprites as there are to draw
    for (loop = 0; loop < sprite.number; loop++)

        //Only do this if the particular sprite's countdown/delay counter has reached 0 (counting down from another method not seen here)
        if (sprite.delay[loop]<0)

            moveQuadNumber(loop); //this method will move the sprite that corresponds to the number loops so we can move through the entire batch and move each individual sprite

        
    

但是,我对此并不完全满意,因为有很多代码重复。除了使用这两种方法之外,有什么方法可以使用第一种方法并以某种方式将附加检查“滑流”到 for 循环中?或者以其他方式减少我在这里的重复?这是一个简单的例子,还有其他的,目前我有多种方法都非常相似。

编辑

如前所述,以上内容有所简化。我可以有一些 for 循环来检查另一个值(例如延迟除外),有些可以检查 2 个条件。

【问题讨论】:

为方法添加一些参数。根据参数的值,您可以采取不同的操作。 您能举个例子解释一下@B.J.Smegma 吗?谢谢 查看 Claudiu 的回答。 【参考方案1】:
public void moveQuadBatch(bool checkDelay) 
    for (loop = 0; loop < sprite.number; loop++)
        if (!checkDelay || sprite.delay[loop] < 0) 
             moveQuadNumber(loop);
        
    

现在moveQuadBatch(false) 是您的第一个函数,moveQuadBatch(true) 是您的第二个函数。


至于“插入额外代码”,您基本上是在谈论函数。在 Python 中,一种优雅的方法是将函数传入并将所有逻辑卸载到函数中,例如:

    def moveQuadBatch(predicate=None):
        for loop, sprite in enumerate(self.sprites): 
            if not predicate or predicate(loop, sprite):
                self.moveQuadNumber(loop)

然后你会这样使用它:

inst.moveQuadBatch()  
inst.moveQuadBatch(lambda loop, sprite: sprite.delay[loop] < 0)
inst.moveQuadBatch(lambda loop, sprite: sprite.doesItBlend(loop))

您可以在 Java 中做同样的事情,但不那么简洁:您必须定义一个谓词类和它的实例。这是 B.J. Smegma 提倡的方法。

public interface QuadBatchPredicate 
    public boolean shouldMove(int loop, Sprite sprite);

你的函数应该是这样的:

public void moveQuadBatch(QuadBatchPredicate pred) 
    for (loop = 0; loop < sprite.number; loop++)
        if (pred == null || pred(loop, sprite)) 
             moveQuadNumber(loop);
        
    

public void moveQuadBatch() 
    moveQuadBatch(null);

然后你可以使用匿名类来定义谓词:

moveQuadBatch();
moveQuadBatch(new QuadBatchPredicate() 
    public boolean shouldMove(int loop, Sprite sprite) 
        return sprite.delay[loop] < 0;
    
);
moveQuadBatch(new QuadBatchPredicate() 
    public boolean shouldMove(int loop, Sprite sprite) 
        return sprite.doesItBlend();
    
);

比 Python 解决方案略显笨拙,但它抓住了重点。现在,您可以通过将谓词内联地定义为您想要的任何内容,将代码“插入”到函数中。另外,您可以保存常用的,这样您就不会到处重复它们:

QuadBatchPredicate checkBlends = new QuadBatchPredicate() 
    public boolean shouldMove(int loop, Sprite sprite) 
        return sprite.doesItBlend();
    
;

【讨论】:

感谢@Claudiu,减少 cmets?我总是读到那些不评论他们的代码的人的抱怨?关于“循环”变量,第一条评论解释说所有变量/对象都假定存在 - 这是为了避免不相关的代码。没关系,但是,如上所述,这仅适用于 2 种不同的可能性,在我的实际代码中,我还有很多其他的,有些对“延迟”等以外的东西进行了额外的检查......有什么方法可以使用main for 循环,但更改其中的代码以进行我需要检查的任何内容 - 谢谢! :-) @Zippy:你能举一些你做的检查的例子吗?这将有助于整理出一个答案。啊,谢谢我错过了第一条评论,我认为它不相关.. @Zippy:哦,关于更少的 cmets,我的意思是你不应该让 cmets 只说出代码的作用,例如int i; //i will be our loop iteratorfor (i=0; i &lt; 100; i++) //loop i starting from 0 and ending at 99, incrementing by 1 each time 等。我知道sprite[delay] &lt; 0 的意思是“只有在特定精灵的倒计时/延迟计数器达到 0 时才这样做”,不需要拼写出来 =)。实际上,如果您这样拼写,​​则更难阅读。 我明白,请随时编辑 cmets :-) 我总是喜欢尽可能多地发表评论,因为我觉得这会使问题更具可读性。 @Zippy:看看我的编辑是否更符合您的喜好。真的允许你使用任何你想要的谓词。函数式编程 FTW【参考方案2】:

我会为延迟检查创建一个单独的方法,并像这样更改您的方法:

public void moveQuadBatchWithCheck(bool check)
    for (loop = 0; loop < sprite.number; loop++)
        if(check)
            if (sprite.delay[loop]<0)
                moveQuadNumber(loop); 
                
       
       else
           moveQuadNumber(loop);
           
    

那么当你想检查调用方法时,使用 true 在参数中。

虽然不确定这是否是您正在寻找的,但我希望它会有所帮助。

【讨论】:

同意,请参阅主要问题中的编辑。谢谢:-) 你说得对。我正在打电话,所以我花了一段时间来回答这个问题。现在我看到了你的回答,我觉得自己很愚蠢。【参考方案3】:

制作这样的界面:

public interface MyInteface 
void do_something(int loop);

根据您的需要对该接口进行不同的实现,例如

public class MyInterfaceImpl 
    public void do_something(int loop) 
         if (!checkDelay || sprite.delay[loop] < 0) 
              moveQuadNumber(loop);
         
    

那么你的方法可能看起来很简单:

public void moveQuadBatch(MyInterface interface) 
    for (int loop = 0; loop < sprite.number; loop++)
        interface.do_something(loop)
    

【讨论】:

对@B.J.Smegma 非常感兴趣。所以基本上,我会在 MyInterfaceImpl 类中为我需要的每个可能的结果创建一个方法,然后把它放在我的循环中? 你将为你在 for 循环中所做的每一件不同的事情创建接口的实现。然后,您可以根据需要使用这些不同的实现来调用您的方法。 基本上是map的精简实现,而我的是filter的精简实现..我不喜欢Java 你是说我需要为每个可能的结果定义一个不同的接口/类吗?或者,例如在同一接口中有一个“doSomething(int loop)”,然后是一个 doSomethingElse(int loop)' 方法。如果是后者,我将如何调用所需的任何方法?我不能显式输入 interface.doSomethingElse(loop) ,因为这又意味着,有多个 moveQuadBatch() 方法会破坏目的。或者也许我不完全理解这一点?谢谢!【参考方案4】:

您可以为您的精灵添加“效果”。

public class Sprite 
    private boolean active = true;
    private ArrayList<Effect> effects = new ArrayList<>();

    public void update(int time) 
        for(Effect e: effects) 
            e.update(this, time);
        
    

    public void addEffect(Effect effect) 
        effects.add(effect);
    

    public void setActive(boolean active) 
        this.active = active;
    


public interface Effect 
    void update(Sprite sprite, int time);


public class Delay implements Effect 
    private int delay;

    public Delay(int delay) 
        this.delay = delay;
    

    public void update(Sprite sprite, int time) 
        delay -= time;
        if(delay > 0) sprite.setActive(false);
        else sprite.setActive(true);
    

【讨论】:

以上是关于在 Java for 循环中插入额外代码的主要内容,如果未能解决你的问题,请参考以下文章

c#通过for循环多次向数据库中插入数据。

如何在SQLserver中利用循环语句插入大量的数据

在 for 循环中插入查询无法正常工作

PHP 不会从 for 循环在数据库中插入重复项

sql 循环插入数据

使用for循环在数字中插入逗号不起作用