0

I'm trying to understand compile versus run-time computation in java. I have the following enum

public enum SightSensor{

  NORTH (new MapLocation[]{new MapLocation(0,1), 
                         new MapLocation(0,2),
                         new MapLocation(0,3)}),
  SOUTH (new MapLocation[]{new MapLocation(0,-1), 
                        new MapLocation(0,-2),
                        new MapLocation(0,-3)});

  private final MapLocation[] locs;

  SightSensor(MapLocation[] locs){
    this.locs = locs;
  }

  public static MapLocation[] getLocs(Direction dir){
    if (dir == Direction.NORTH)
      return NORTH.locs;
    if (dir == Direction.SOUTH)
      return SOUTH.locs;
  }
};

In words, I want to define a constant mapping between a Direction and an array of MapLocations. (Perhaps this is the wrong way to do this? I'm new to Java.) Now, if I write

MapLocation[] locs = SightSensor.getLocs(Direction.SOUTH_WEST);

inside a loop in the code, I find that there is a cost overhead the first time the code is called, implying to me it is somehow being computed/instantiated at run time. If instead I just directly code

MapLocation[] locs = new MapLocation[]{new MapLocation(0,1),
                           new MapLocation(0,2),
                           new MapLocation(0,3)};

there is no cost overhead. I don't understand the difference. Does the compiler do some weird sort of just-in-time computation?

andyInCambridge
  • 1,215
  • 2
  • 13
  • 27
  • Can you explain how you are measuring the cost overhead? – The Nail Jan 02 '12 at 21:33
  • Also, your example does not compile; you need some kind of else statement in `getLocs`, because now there are paths without a return value (when `dir` is neither NORTH nor SOUTH) – The Nail Jan 02 '12 at 21:37
  • Nail, sorry about that, attempted to simplify the code. Measuring in bytecode. – andyInCambridge Jan 02 '12 at 22:04
  • Ok. But...I assumed the cost overhead was time, not space? :-) How are you relating bytecode size to first/second time running? – The Nail Jan 02 '12 at 22:15

3 Answers3

3

It seems that the cost you're seeing is the class-loading cost: the first time the code accesses a class, the class-loader loads its binary (.class file) into memory. This is a one time cost that for most practical purposes is negligible.

Moreover:

Now, if I write ... inside a loop in the code, I find that there is a cost overhead the first time the code is called,

How did you measure this cost? It is nearly impossible to measure the time cost of a single operation. You can measure the time needed to carry out xM passes thru a loop and then you can divide to get the amortized cost. However, measuring a single operation is difficult: you may be getting a Garbage Collection cycle, a thread-related context switch, etc. Moreover, the JIT (Just In Time) Compiler does not kick the first time a statement is executed, so measuring a single operation will usually give you a much higher cost than amortized cost over N operations.

FWIW, I would write getLocs() as follows:

public static MapLocation[] getLocs(Direction dir) {
  return valueOf(dir.name()).locs;
}

Alternatively, you can use replace the SightSensor enum with a variable of type EnumMap:

EnumMap<Direction, MapLocation[]> map = new EnumMap(Direction.class);
map.put(Direction.NORTH, new MapLocation[] {  new MapLocation(0, 1), 
                                              new MapLocation(0, 2),
                                              new MapLocation(0, 3) });
map.put(Direction.NORTH, new MapLocation[] {  new MapLocation(0, -1), 
                                              new MapLocation(0, -2),
                                              new MapLocation(0, -3) });

Then, getLocs() calls simply become map.get(dir)

Itay Maman
  • 30,277
  • 10
  • 88
  • 118
2

Does the compiler do some weird sort of just-in-time computation?

Yes, the Java run-time does use statistics to optimize the code as it runs:

http://docs.oracle.com/javase/6/docs/technotes/tools/share/jstat.html

Nothing weird about it.

This might be pertinent as well:

Real differences between "java -server" and "java -client"?

Personally, I think you should write the code to be as easy to read as possible and not worry about optimization. The speedup probably isn't significant.

Community
  • 1
  • 1
duffymo
  • 305,152
  • 44
  • 369
  • 561
0

This is not really an answer, but a tip: Make getLocs non-static and just return the locs of the current enum:

public MapLocation[] getLocs(){
    return locs;
}

Instead of SightSensor.getLocs(someDir) you then call someDir.getLocs().

This way you avoid having to enumerate all members of the enum.

The Nail
  • 8,355
  • 2
  • 35
  • 48