Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A complex key for guavas Cache (shifting)

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.

like image 611
Marcel Jaeschke Avatar asked Nov 23 '11 10:11

Marcel Jaeschke


People also ask

Is Guava cache distributed cache?

Hazelcast is for distributed caching, meaning many services share the same cache, whereas Guava/Caffeine is a local cache per each service (not shared).

What is Guava caching?

Guava provides a very powerful memory based caching mechanism by an interface LoadingCache<K,V>. Values are automatically loaded in the cache and it provides many utility methods useful for caching needs.

Is Guava in memory cache?

Guava Cache is an in-memory cache used in applications. The following operations can be performed on a cache: Insert data.

Where is Guava cache stored?

Guava Caches store values in RAM.


2 Answers

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));
like image 143
bjmi Avatar answered Oct 23 '22 18:10

bjmi


It's probably faster (if the difference is measurable at all), but the pair class will make your code much better to understand or reuse. I'd go with a generic Pair class:

public final class Pair<L, R> {

    private final L left;
    private final R right;

    private Pair(L left, R right) {
        this.left = left;
        this.right = right;
    }

    public static <L,R>Pair<L,R> of(L left, R right){
        return new Pair<L, R>(left,right);
    }

    @Override
    public boolean equals(final Object obj) {
        if (obj instanceof Pair) {
            final Pair<?,?> other = (Pair<?,?>) obj;
            return Objects.equal(left,  other.left)
                && Objects.equal(right, other.right);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(left, right);
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                      .add("left", left)
                      .add("right", right)
                      .toString();
    }

}

Once you have that in your code base, you will find more than one use for it. Bit shifting is not really Java-like (although many others will disagree).

Guava docs

like image 30
Sean Patrick Floyd Avatar answered Oct 23 '22 19:10

Sean Patrick Floyd