Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class.forName() caching

In one of my applications I am using the following:

public void calculate (String className)
{
  ... 
  Class clazz = Class.forName(className);
  ...
}

This function is called several times / second. There are about 10 possible class names. And while I do realize there is some internal caching inside this function, I think this caching is only available on native level.

For this reason I am starting to wonder if I should add my own caching.

private static Map<String,Class> classMap;

public void calculate (String className)
{
  ... 
  Class clazz = classMap.get(className);
  if (clazz == null) 
  {
      clazz = Class.forName(className);
      if (classMap == null) classMap = new HashMap<String, Class>(40);
      classMap.put(className, clazz);
  }
  ...
}

Will this be a performance gain or does it really make no difference ?

Thank you in advance

like image 467
bvdb Avatar asked Aug 14 '13 12:08

bvdb


People also ask

What is forName () method?

forName(String name, boolean initialize, ClassLoader loader) Returns the Class object associated with the class or interface with the given string name, using the given class loader.

Why do we use class forName?

The forName() method of java. lang. Class class is used to get the instance of this Class with the specified class name. This class name is specified as the string parameter.

What is the use of forName method in JDBC?

forName() The most common approach to register a driver is to use Java's Class. forName() method, to dynamically load the driver's class file into memory, which automatically registers it. This method is preferable because it allows you to make the driver registration configurable and portable.

How do I load a class using forName?

Load class with forName() method in Java The class object associated with the class with the given string name can be returned with the method java. lang. Class. forName(String name, boolean initialize, ClassLoader loader), using the class loader that is used to load the class.


3 Answers

I wrote a little script to calculate the execution time of both functions.

This is the Main class that I used.

public class Benchmark
{
  public static void main(String... pArgs)
  {
    // prepare all data as much as possible.
    // we don't want to do this while the clock is running.
    Class[] classes = {Object.class, Integer.class, String.class, Short.class, Long.class, Double.class,
                       Float.class, Boolean.class, Character.class, Byte.class};
    int cycles = 1000000;
    String[] classNames = new String[cycles];
    for (int i = 0; i < cycles; i++) 
    {
      classNames[i] = classes[i % classes.length].getName();
    }

    // THERE ARE 2 IMPLEMENTATIONS - CLASSIC vs CACHING
    Implementation impl = new Caching();   // or Classic();

    // Start the clocks !
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < cycles; i++)
    {
      impl.doStuff(classNames[i]);
    }
    long endTime = System.currentTimeMillis();

    // calculate and display result
    long totalTime = endTime - startTime;
    System.out.println(totalTime);
  }
}

Here is the classic implementation that uses Class.forName

  private interface Implementation
  {
    Class doStuff(String clzName);
  }

  private static class Classic implements Implementation
  {
    @Override
    public Class doStuff(String clzName)
    {
      try
      {
        return Class.forName(clzName);
      }
      catch (Exception e)
      {
        return null;
      }
    }
  }

Here is the second implementation that uses a HashMap to cache the Class objects.

  private static class Caching implements Implementation
  {
    private Map<String, Class> cache = new HashMap<String, Class>();

    @Override
    public Class doStuff(String clzName)
    {
      Class clz = cache.get(clzName);
      if (clz != null) return clz;
      try
      {
        clz = Class.forName(clzName);
        cache.put(clzName, clz);
      }
      catch (Exception e)
      {
      }
      return clz;
    }
  }

The results:

  • 1100 ms without caching.
  • only 15 ms with caching.

Conclusion:

  • Is it a significant difference --> yes !
  • Does it matter for my application --> not at all.
like image 98
bvdb Avatar answered Oct 21 '22 07:10

bvdb


Will this be a performance gain or does it really make no difference?

I would be astonished if it made a significant difference - and if you're only calling it "several times per second" (rather than, say, a million) it's really not worth optimizing.

You should at least try this in isolation in a benchmark before committing to this more complicated design. I would strongly expect Class.forName to be caching this anyway, and adding more complexity into your app does no good.

like image 29
Jon Skeet Avatar answered Oct 21 '22 06:10

Jon Skeet


Class.forName() does two things:

  1. it fetches a loaded class from the classloader
  2. if no such class is found, it tries to load it.

Part #1 is pretty quick. #2 is where the real work starts (where the JVM might hit the hard disk or even the network, depending on the classloader). And if you pass the same parameters in, then all but the first invocations will never get to step #2.

So no: it's probably not worth optimizing.

like image 42
Joachim Sauer Avatar answered Oct 21 '22 05:10

Joachim Sauer