Tag Archives: Java8

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.

Java 8: Map does not look up keys which obviously contains!

We have experienced strange bug in our application: Map::keySet() returned keys which was not possible lookup using Map::get(T key) even during iteration over its result. Strange, right?

map.keySet().foreach (key->{
if (!map.containsKey(key)) {
throw new RuntimeException("Huh?");   //this actually happens!
}
});

Debugging of that was hard. We had to  exclude factors like other threads, broken build, etc. But in the end we started to be suspicious about implementation of hashCode() and equals() method of object used as key in map. Close but not hit.

Method hashCode was implemented in the way that it returned same hashCode for most of possible values of key. That put most of values into single bucket in internal Map structure. It was hard to calculate reliable hashCode in this case so programmers intention was to focus on equals() method. Of course that means that often many values should be tested by equals() method, but for small data it is no issue.

But for case when many items fall into same bucket was introduced new optimization in Java8. If programmer delivers poor hashCode() implementation AND key class implements Comparable interface then Java tries to use tree instead of list in bucket. See comment in source code.

Therefore it is really necessary to correctly implement Comparable interface. And, you are right, our was implemented poorly:


int compareTo(T o) {
if (o.equals(this)) {
return 0;
}

return 1;
}

Therefore it depends on "this" object during compareTo() call. When compareTo() was called on A then B was considered as bigger.When compareTo() was called on B then A was considered as bigger. Although they still are same two objects. So our implementation broke compareTo() contract. When during inserting into bucket tree was compareTo() called on A but during lookup on B then lookup failed.

Solution was to correctly implement compareTo().

Execution limiter using lambda

Execution limiter class may help in situations when something must be executed only once per specified time. Use cases:

  • Computing large data and want to print progress only every 10 seconds
  • Inputs are changing often but you do not wan’t to calculate result more often than once per second

Typical is to use variable storing time stamp of last execution and condition not allowing execution sooner than X. But that is not truly encapsulated solution, right? I use helper class, usage is following:

ExecutionsLimiter limiter = new ExecutionsLimiter(1000, false);
for (int i=0;i<10000000;++i) {
    limiter.tryExec(()->{
        //printed at most once per second
        System.out.printf("quot;Current progress is %d\n", i);
    })

    calcHeavyStuff(i);
}

Class itself looks like:

public class ExecutionsLimiter {
    private long lastRepeatTimestamp;
    private long intervalMsec;

    public ExecutionsLimiter(long intervalMsec, boolean mayExecImmediatelly) {
        this.intervalMsec = intervalMsec;
        this.timeSuplier = timeSuplier;

        reset(mayExecImmediatelly);
 }

 public void tryExec(Runnable block) {
     long currentTimestamp =System.currentTimeMillis();

     if (currentTimestamp - lastRepeatTimestamp > intervalMsec) {
         lastRepeatTimestamp = currentTimestamp;
         block.run();
     }
 }

 public void reset(boolean mayExecImmediatelly) {
      lastRepeatTimestamp = mayExecImmediatelly ? Long.MIN_VALUE : System.currentTimeMillis();
 }
}

There is also method reset(). It may be used for use case like:

  • Process files in directories and print current file every 5 seconds
  • Print at least one file per directory

In that case it may happen that second request won’t be fulfilled when processing time of some directories will be less than 5 seconds. Simple call limiter.reset(true) when entering directory will reset limiter and first tryExec will pass.

Using this tool, you can get rid of conditions in your code and make it cleaner and easier to understand.