Sunday, November 15, 2015

Stubbing a method with Class field

Consider the scenario where you have to stub a method using when. In a case where parameter is a class not an object then the Matchers.any will not help in that case. Following is the code to be tested and one wrong way of stubbing.
// code to be tested
Long primaryKey = 12345L;
final App app = getEntityManager().find(App.class, primaryKey);

// stubbing the find method
when(em.find(Matchers.any(Class.class), Matchers.same(primaryKey)))
.thenReturn(app);
Instead of using Matchers.any we should use Matchers.isA as the way of stubbing. Following is correct way of stubbing in this setup.
when(em.find((Class) Matchers.isA(Class.class), Matchers.same(primaryKey)))
.thenReturn(app);
The original answer was found on stackoverflow.

Wednesday, October 07, 2015

A Better String Formatter for Java

After looking into String format techniques used in current Java implementation I found some interesting article about perfromace related in stackoverflow. Then I started checking out a better way to still use the same method type as string format since its cleaner and readable. Following is the code benchmark code (partly taken from stackoverflow link).

 public static void main(String[] args) throws Exception {      

  final int ITERATION_COUNT = 10000000;

  // contact using plus
  long start = System.currentTimeMillis();
  for( int i=0;i<ITERATION_COUNT; i++){
   String s = "Hi " + i + "; Hi to you " + i*2;
  }
  long end = System.currentTimeMillis();
  System.out.println("Concatenation = " + ((end - start)) + " millisecond") ;

  // concat using string format
  start = System.currentTimeMillis();
  for( int i=0;i<ITERATION_COUNT; i++){
   String s = String.format( "Hi %s; Hi to you %s",i, + i*2);
  }
  end = System.currentTimeMillis();
  System.out.println("Format = " + ((end - start)) + " millisecond");

  // concat using string builder
  start = System.currentTimeMillis();
  for( int i=0;i<ITERATION_COUNT; i++){
   String s = new StringBuilder("Hi ").append(i)
     .append("; Hi to you ").append(i*2).toString();
  }
  end = System.currentTimeMillis();
  System.out.println("StringBuilder = " + ((end - start)) + " millisecond");

  // fancy formatter
  start = System.currentTimeMillis();

  // Send all output to the Appendable object sb
  for( int i=0;i<ITERATION_COUNT; i++){
   StringBuilder sb = new StringBuilder();
   Formatter formatter = new Formatter(sb, Locale.US);
   String s = formatter.format("Hi %s; Hi to you %s", i, + i*2).toString();
  }
  end = System.currentTimeMillis();
  System.out.println("Formatter = " + ((end - start)) + " millisecond");

  // concat using my-format
  start = System.currentTimeMillis();
  for( int i=0;i<ITERATION_COUNT; i++){
   String s = myFormat( "Hi %s; Hi to you %s",i, (i*2));
  }
  end = System.currentTimeMillis();
  System.out.println("My = " + ((end - start)) + " millisecond");
 }

And following are the results after iterating over 10000000 times.
  • Concatenation = 740 millisecond
  • Format = 9942 millisecond
  • StringBuilder = 540 millisecond
  • Formatter = 9586 millisecond
  • MyFormatter = 2078 millisecond (almost 5 times better than other formatters)
And following is the code for MyFormat method
 public static String myFormat(String string, Object... objects) {
  StringBuilder result = new StringBuilder();
  boolean previousWasPercentage = false;
  int i = 0;
  for (char c : string.toCharArray()) {
   if (c == '%') {
    previousWasPercentage = true;
    continue;
   }
   if (previousWasPercentage){
    previousWasPercentage = false;
    if ( c == 's') {
     result.append(objects[i]);
     i++;
     continue;
    } else {
     result.append("%").append(c);
     continue;
    }
   }
   result.append(c);
  }
  return result.toString();
 }