[英]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? 在Java 8中是否存在方法的implements
关键字的任何模拟?
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: 一个包含3个静态方法的库“实现”这个功能接口:
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. 在将来,我希望能够互换地使用对这3种方法的任何引用作为参数。 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)
? 如何在编译时确保LongHashes::xorHash
, LongHashes::continuingHash
LongHashes::randomHash
和LongHashes::randomHash
与LongHasher.hash(long x)
具有相同的签名?
I had wished for this too, in the past, but no you can't do that. 在过去,我也曾希望这样做,但不,你不能这样做。 But you know. 但是你知道。 There was Java before Java 8. Do this instead: 在Java 8之前有Java。请改为:
enum LongHashes implements LongHasher {
XOR {
@Override
public int hash(long x) { ... }
},
CONTINUING {
@Override
public int hash(long x) { ... }
},
RANDOM {
@Override
public int hash(long x) { ... }
}
}
And then: 然后:
public static void main(String[] args) {
LongHashMap map = createHashMap(LongHashes.RANDOM);
...
}
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. 如果您愿意,可以将它们声明为public
并使用而不是方法引用。
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. 如果您担心这些静态lambda将在运行时挂在内存中,您可以将此声明移动到单独的类(例如,嵌套),该类编译但从未加载。
You could declare function objects, instead of methods. 您可以声明函数对象而不是方法。
class LongHashes {
static final LongHasher xorHash = x -> {
return (int)(x ^ (x >>> 32));
};
... etc
LongHashMap map = createHashMap(LongHashes.randomHash);
One way would be to return a LongHasher
directly from the LongHashes
class: 一种方法是返回一个LongHasher
直接从LongHashes
类:
class LongHashes {
private static int xorHashImpl(long x) {
return (int)(x ^ (x >>> 32));
}
static LongHasher xorHash() {
return LongHashes::xorHashImpl;
}
}
but that adds some code to your LongHashes
class and ties it to the LongHasher
interface, which may not be desirable (although that's essentially what you are asking for). 但是这会为你的LongHashes
类添加一些代码并将它与LongHasher
接口联系起来,这可能并不理想(尽管这基本上就是你所要求的)。
Or just create 3 classes which implement LongHasher. 或者只创建3个实现LongHasher的类。 When you need a LongHasher, get or create an instance and pass it: 当您需要LongHasher时,获取或创建一个实例并传递它:
LongHasher longHasher = ... // new RandomLongHasher(), factory, .......
LongHashMap map = createHashMap(longHasher);
Writing functions as static methods here: 在这里编写静态方法的函数:
We're not forced to use lambdas everywhere. 我们并没有被迫在任何地方使用lambdas。
Although I find Tagir's answer a nice hack, it's easy to forget adding the private constant when one creates a new hasher. 虽然我发现Tagir的答案是一个很好的黑客,但是当一个人创建一个新的哈希时,很容易忘记添加私有常量。
As usual, when dealing with potential refactoring problems, I think that testing is the answer: 像往常一样,在处理潜在的重构问题时,我认为测试就是答案:
public class LongHashesTest {
@Test
public void xorHash() {
LongHasher xorHash = LongHashes::xorHash;
assertEquals(1768181579, xorHash.hash(34312465426524234l));
}
@Test
public void continuingHash() {
LongHasher continuingHash = LongHashes::continuingHash;
assertEquals(1529080340, continuingHash.hash(74543524355l));
}
@Test
public void randomHash() {
LongHasher randomHash = LongHashes::randomHash;
assertEquals(-1100764221, randomHash.hash(4343245345432154353l));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.