A complex key for guavas Cache (shifting)

Marcel Jaeschke picture Marcel Jaeschke · Nov 23, 2011 · Viewed 8.4k times · Source

I have a point object:

  class Point {
    final int x,y;
    ...
  }

Because these points will be used/created all over the place in my code, I want to start using guavas cache. Unfortuinally the CacheLoader only accept one parameter. Another question here on stackoverflow use a pair object for a similar problem. But I don't like the idea to create a dummy object for every cache request. So I come up with my own workaround:

Because the object is specified by the x and y, I think I can merge(shift) both values into a long, which will be my key.

void test(int x, int y) {
    Long key = (long) ((long) (x) << Integer.SIZE | y);
    Point point = cache.get(key);
}

CacheLoader<Long, Point> loader = new CacheLoader<Long, Point>() {
    public Point load(Long key) throws Exception {
    final int x,y;
        // shift magic
        x = (int) (key >> Integer.SIZE);
        y = key.intValue();
        return new Point(x, y);
    }
};

I'm actually a shift noob. Will this work? Did I miss something? Is this "faster" than the pair class? That's my question!

Yes, I test the code and it works so far I can tell.

Answer

bjmi picture bjmi · Nov 23, 2011

How about this? Your Point class must correctly implement equals() and hashcode().

static class Points {
  static final Interner<Point> INTERNER = Interners.newStrongInterner();

  public static Point cached(final int x, final int y) {
    return INTERNER.intern(new Point(x, y));
  }
}

Your actual purpose was to cache equal objects, right? Than this will suffice your needs. Usage:

Point center = Points.cached(0, 0);

Or an adjusted version of your cache example:

CacheLoader<Point, Point> loader = new CacheLoader<Point, Point>() {
  @Override
  public Point load(final Point point) {
    return point;
  }
}
...
Point center = cache.get(new Point(0, 0));