Sunday, May 12, 2013

Java: using class variables for performance

I often see code like this:

    public Date parse( String s ) throws ParseException  
    {  
       SimpleDateFormat parser = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );  
       Date date = parser.parse( s );  
       return date;  
    }  

Creating an object that never changes, as the SimpleDateFormat object, inside the function is a huge waste of time.

The code would be more efficient if the object was created only once as a data member:


    private final SimpleDateFormat parser_ = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );  
    public Date parse( String s ) throws ParseException  
    {  
       Date date = parser_.parse( s );  
       return date;  
    }  

This is a test program to check how fast the new code is. See some actual numbers on a Mac OS X after the program.


import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;


public class test {

   public static class SlowVersion {
      public Date parse( String s ) throws ParseException {
         SimpleDateFormat parser = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
         Date date = parser.parse( s );
         return date;
      }
   }

   public static class FasterVersion {   
      private final SimpleDateFormat parser_ = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
      public Date parse( String s ) throws ParseException
      {
         Date date = parser_.parse( s );
         return date;
      }
   }

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

      System.out.println( "Tested with JRE " + System.getProperty("java.version") );
      System.out.println( "Running on "+ System.getProperty("os.name") +
            " " + System.getProperty("os.version") );

      long startTime = System.currentTimeMillis();
      SlowVersion slow = new SlowVersion();
      for( int i = 0; i < 1000; i++ )
         slow.parse( "2013-03-14 12:34:56" );
      long endTime = System.currentTimeMillis();
      System.out.println( "Execution time:" + (endTime-startTime) + " ms" );

      startTime = System.currentTimeMillis();
      FasterVersion faster = new FasterVersion();
      for( int i = 0; i < 1000; i++ )
         faster.parse( "2013-03-14 12:34:56" );
      endTime = System.currentTimeMillis();
      System.out.println( "Execution time:" + (endTime-startTime) + " ms" );
   }
}   


These are three runs with that code on a Mac OS X 10.7 with JRE 1.7:


Tested with JRE 1.7.0_21
Runnign on Mac OS X 10.7.5
Execution time:331 ms
Execution time:83 ms

Tested with JRE 1.7.0_21
Runnign on Mac OS X 10.7.5
Execution time:322 ms
Execution time:114 ms

Tested with JRE 1.7.0_21
Runnign on Mac OS X 10.7.5
Execution time:368 ms
Execution time:102 ms


The small change makes the code about three times faster.

It is optimization in the small, but it is a simple one. Several small optimizations may add up in the end.

If you test on a different environment: please post your numbers as comments.  Just out of curiosity, to see how other operating systems and JRE perform.


No comments:

Post a Comment