Search code examples
javajava-8functional-interface

How to ensure at Java 8 compile time that a method signature "implements" a functional interface


Is there in Java 8 any analogue for implements keyword for methods?

Let's say I have a functional interface:

@FunctionalInterface
interface LongHasher {
    int hash(long x);
}

And a library of 3 static methods "implementing" this functional interface:

class LongHashes {
    static int xorHash(long x) {
        return (int)(x ^ (x >>> 32));
    }
    static int continuingHash(long x) {
        return (int)(x + (x >>> 32));
    }
    static int randomHash(long x) {
         return xorHash(x * 0x5DEECE66DL + 0xBL);
    }
}

In the future I want to be able to interchangeably use any of references to these 3 methods as a parameter. For example:

static LongHashMap createHashMap(LongHasher hasher) { ... }
...
public static void main(String[] args) {
    LongHashMap map = createHashMap(LongHashes::randomHash);
    ...
}

How can I ensure at compile time that LongHashes::xorHash, LongHashes::continuingHash and LongHashes::randomHash have the same signature as LongHasher.hash(long x)?


Solution

  • There's no such syntax construction you're asking for. However you can create a static constant where you explicitly assign the method reference to your interface:

    class LongHashes {
        private static final LongHasher XOR_HASH = LongHashes::xorHash;
        private static final LongHasher CONTINUING_HASH = LongHashes::continuingHash;
        private static final LongHasher RANDOM_HASH = LongHashes::randomHash;
    
        static int xorHash(long x) {
            return (int)(x ^ (x >>> 32));
        }
        static int continuingHash(long x) {
            return (int)(x + (x >>> 32));
        }
        static int randomHash(long x) {
             return xorHash(x * 0x5DEECE66DL + 0xBL);
        }
    }
    

    This way your compilation will break if either method signature or interface changes in incompatible way. If you want you may declare them public and use instead of method references.

    If you care that these static lambdas will be hanging in memory at runtime, you can move this declaration to the separate class (for example, nested), which compiles but never loaded.