最近由雅和提出的堆棧溢出問題引起了我興趣:怎麼確保Java 8 編譯時,一個方法簽名實現了函數式接口。這個是一個好問題。我們假設下面的定義:
@FunctionalInterface
interface LongHasher {
int hash(long x);
}
這個類型強加了一個清晰的約定。實現類必須提供一個單獨的hash方法 ,傳一個長整型參數,返回一個整型值。當使用lambdas或方法引用時,這個hash()方法名就不再相關了並且結構類型long–>int 也滿足。
在他的問題中,雅和想要強制三個靜態方法上的類型(我修改的例子):
class LongHashes {
// OK
static int xorHash(long x) {
return (int)(x ^ (x >>> 32));
}
// OK
static int continuingHash(long x) {
return (int)(x + (x >>> 32));
}
// Yikes
static int randomHash(NotLong x) {
return xorHash(x * 0x5DEECE66DL + 0xBL);
}
}
他想要Java 編譯器報怨randomHash()與LongHasher不一致。
這樣很容易產生一個編譯錯誤,當然,用函數註解(方法引用)可以自然地給LongHasher實例的靜態方法賦值。
// OK
LongHasher good = LongHashes::xorHash;
LongHasher alsoGood = LongHashes::continuingHash;
// Yikes
LongHasher ouch = LongHashes::randomHash;
但是這樣不太簡潔。類型約束應該直接強加在static方法上面。
用Java的方式怎麼做到這些呢?
當然,用註解
我敢打賭下面的模式將會出現在JDK 10裏面。
class LongHashes {
// Compiles
@ReferenceableAs(LongHasher.class)
static int xorHash(long x) {
return (int)(x ^ (x >>> 32));
}
// Compiles
@ReferenceableAs(LongHasher.class)
static int continuingHash(long x) {
return (int)(x + (x >>> 32));
}
// Doesn't compile
@ReferenceableAs(LongHasher.class)
static int randomHash(NotLong x) {
return xorHash(x * 0x5DEECE66DL + 0xBL);
}
}
事實上,今天你就能實現這樣一個註解並且寫下你自己的註解處理器來驗證這些方法。期待另一個偉大的註解。