Lambda: simplify method calls

There is important part of good programmers skills - ability to detect duplicity. Over years I have developed it for various situations. But recently I have added new situation - duplicity in calling methods with many parameters. And especially with many parameters in local scope. Take a look on following example:

package test; 

import java.awt.Graphics; 

public class NaiveRenderer { 
    public void render(Graphics g, int paramA, boolean paramB, double paramC, String paramD) { 
        int calculatedA = paramA+42; 
        if (paramA<100) { 
            renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, -1.0); 
        } else if (paramA<10) { 
            renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, -0.2); 
        } else if (paramA==0) { 
            renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, 0.0); 
        } else if (paramA>100) { 
            renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, 1.0); 
        } else if (paramA>10) { 
            renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, 0.2); 
        } else { 
            renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", calculatedA, 0.0); 
        } 
    } 
    
    public void renderSubpart(Graphics g, boolean paramB, double paramC, String paramD, int calculatedA, double calculatedB) { 
        //...actual code 
    } 
}

Obviously, there is huge duplicity in renderSubpart calls. Calculation of some parameters is repeated many times. Let’s improve it:

package test; 

import java.awt.Graphics; 

public class BetterRenderer { 
    public void render(Graphics g, int paramA, boolean paramB, double paramC, String paramD) { 
        int calculatedA = paramA+42; 
        boolean newParamB = !paramB; 
        double newParamC = paramC*22.3; 
        String newParamD = paramD+" oh"; 
        
        if (paramA<100) { 
            renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, -1.0); 
        } else if (paramA<10) { 
            renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, -0.2); 
        } else if (paramA==0) { 
            renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, 0.0); 
        } else if (paramA>100) { 
            renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, 1.0); 
        } else if (paramA>10) { 
            renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, 0.2); 
        } else { 
            renderSubpart(g, newParamB, newParamC, newParamD, calculatedA, 0.0); 
        } 
    } 
    
    public void renderSubpart(Graphics g, boolean paramB, double paramC, String paramD, int calculatedA, double calculatedB) { 
        //...actual code 
    } 
}

Hm. So we have bloated scope by three new local variables. And we have to name it. Plus there is still problem with many similar calls to the renderSubpart. But only one parameter varies. Let’s improve that:

package test; 

import java.awt.Graphics; 

public class EvenBetterRenderer { 
    public void render(Graphics g, int paramA, boolean paramB, double paramC, String paramD) { 
        double calculatedB; 
        
        if (paramA<100) { 
            calculatedB = -1.0; 
        } else if (paramA<10) { 
            calculatedB = -0.2; 
        } else if (paramA==0) { 
            calculatedB = 0.0; 
        } else if (paramA>100) { 
            calculatedB = 1.0; 
        } else if (paramA>10) { 
            calculatedB = 0.2; 
        } else { 
            calculatedB = 0.0; 
        } 
        
        renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", paramA+42, calculatedB); 
    } 
    
    public void renderSubpart(Graphics g, boolean paramB, double paramC, String paramD, int calculatedA, double calculatedB) { 
        //...actual code 
    } 
}

So now we reduced number of added local variables to one. Great, but I don’t like decoupling of condition and method call. Block of condition just set calculatedB which is later used for calling renderSubpart. Can’t we improve that? I realized that I can wrap parameters into local lambda function like this:

package test; 

import java.awt.Graphics; 
import java.util.function.Consumer; 

public class LambdaRenderer { 
    public void render(Graphics g, int paramA, boolean paramB, double paramC, String paramD) { 
        Consumer<Double> renderSubpartLambda = (calculatedB)->renderSubpart(g, !paramB, paramC*22.3, paramD+" oh", paramA+42, calculatedB); 
        
        if (paramA<100) { 
            renderSubpartLambda.accept(-1.0); 
        } else if (paramA<10) { 
            renderSubpartLambda.accept(-0.2); 
        } else if (paramA==0) { 
            renderSubpartLambda.accept(0.0); 
        } else if (paramA>100) { 
            renderSubpartLambda.accept(1.0);
        } else if (paramA>10) { 
            renderSubpartLambda.accept(0.2); 
        } else { 
            renderSubpartLambda.accept(0.0);
        } 
    } 
    
    public void renderSubpart(Graphics g, boolean paramB, double paramC, String paramD, int calculatedA, double calculatedB) { 
        //...actual code 
    } 
}

So I have defined renderSubpartLambda that receives single varying parameter and fill all other parameters that shares value over all calls. This is possible because Lambda function, unlike methods, have access to the local scope (parameters, local variables). Lambda is then executed from exact position withing condition blocks with only with single important parameter.

This technique is usable in all situations where it would be hard to define helper method because number of passed parameters would be too high. Btw. this solution is language independent - I have used it in JavaScript too.

Last blog articles:
Hello Ruby: Dobrodružné programování
Edison EdBlocks: Using remote control
Edison 2.0 received!
JS debug: visually compare two objects or JSONs in browser
4 tips to return multiple values

Last tweets: