Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a non-changing enum method be optimized by the JVM at runtime?

Can the JVM perform runtime optimization in the following scenario?

We've got the following situation, we have this interface:

public interface ECSResource {
    default int getFor(final Entity entity) {
        return ResourceRetriever.forResource(this).getFor(entity);
    }
}

And a concrete implementation such as:

private static enum TestResources implements ECSResource {
    TR1, TR2;
}

Would the JVM be able to figure out (at runtime) that an enum instance such as TestResources.TR1 belongs to a single ResourceRetriever like ResourceRetriever.forResource(TestResources.TR1)?

In the naive implementation every call to TestResources.TR1.getFor(...) would create a new ResourceRetriever instance.

In this case though, we know that (by code inspection) a call to ResourceRetriever.forResource(this) will call the following:

public class ResourceRetriever {
    private final ECSResource resource;

    ResourceRetriever(ECSResource resource) {
        this.resource = resource;
    }

    public static ResourceRetriever forResource(ECSResource resource) {
        return new ResourceRetriever(resource);
    }

    //lots of methods
}

Hence there is nothing that can change at runtime due to random results, rounding errors, etc.

Hence the question: Can the JVM map every enum ECSResource instance to its unique corresponding ResourceRetriever.forResource(this) instance?

Note that it is possible to do such thing by your own, via the following:

private static enum TestResources implements ECSResource {
    TR1, TR2;

    private static final Map<TestResources, ResourceRetriever> retrieverMapping;
    static {
        retrieverMapping = Arrays.stream(TestResources.values())
            .collect(Collectors.toMap(res -> res, ResourceRetriever::forResource));
    }

    @Override
    public int getFor(final Entity entity) {
        return retrieverMapping.get(this).getFor(entity);
    }
}
like image 206
skiwi Avatar asked Nov 05 '14 13:11

skiwi


1 Answers

The semantics of the new keyword almost certainly prohibit what you're wanting to do. (See references both in The Java Language Specification and The Java Virtual Machine Specification.) Your forResource method is always going to return a new object. I don't know of any JVMs that would do what you're trying to do, given that there is no mechanism to determine that only one ResourceRetriever should be created for any given ECSResource. This looks like a form of memoization to me, which would be handled by the language (e.g. Groovy, which has an annotation specifically for this) and not by the runtime (JVM). If Java had reified generics, you could possibly hack such a feature with something like ResourceRetriever<? extends ECSResource> but I can't say whether that would actually work, much less whether it would be a good idea or not.

like image 62
ngreen Avatar answered Oct 30 '22 14:10

ngreen