如何确保在 Java 8 编译时方法签名 "implements" 是功能接口
How to ensure at Java 8 compile time that a method signature "implements" a functional interface
Java 8 中是否有任何类似方法的 implements
关键字?
假设我有一个功能接口:
@FunctionalInterface
interface LongHasher {
int hash(long x);
}
和一个包含 3 个静态方法的库 "implementing" 这个功能接口:
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);
}
}
将来我希望能够互换使用对这 3 种方法的任何引用作为参数。例如:
static LongHashMap createHashMap(LongHasher hasher) { ... }
...
public static void main(String[] args) {
LongHashMap map = createHashMap(LongHashes::randomHash);
...
}
如何在编译时确保 LongHashes::xorHash
、LongHashes::continuingHash
和 LongHashes::randomHash
与 LongHasher.hash(long x)
具有相同的签名?
一种方法是直接从 LongHashes
class:
return LongHasher
class LongHashes {
private static int xorHashImpl(long x) {
return (int)(x ^ (x >>> 32));
}
static LongHasher xorHash() {
return LongHashes::xorHashImpl;
}
}
但这会向您的 LongHashes
class 添加一些代码并将其绑定到 LongHasher
接口,这可能不是您所希望的(尽管这正是您所要求的)。
没有您要求的语法结构。但是,您可以创建一个静态常量,在其中显式地将方法引用分配给您的接口:
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);
}
}
这样,如果方法签名或接口以不兼容的方式更改,您的编译就会中断。如果你愿意,你可以声明它们 public
并使用而不是方法引用。
如果您关心这些静态 lambda 将在运行时挂在内存中,您可以将此声明移动到单独的 class(例如,嵌套),它编译但从不加载。
我过去也希望如此,但不,你不能那样做。但是你知道。 Java 之前有 Java 8. 改为:
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) { ... }
}
}
然后:
public static void main(String[] args) {
LongHashMap map = createHashMap(LongHashes.RANDOM);
...
}
您可以声明函数对象,而不是方法。
class LongHashes {
static final LongHasher xorHash = x -> {
return (int)(x ^ (x >>> 32));
};
... etc
LongHashMap map = createHashMap(LongHashes.randomHash);
或者只创建 3 个 类 来实现 LongHasher。当你需要一个 LongHasher 时,获取或创建一个实例并传递它:
LongHasher longHasher = ... // new RandomLongHasher(), factory, .......
LongHashMap map = createHashMap(longHasher);
这里把函数写成静态方法:
- 让人难以理解
- 听起来像是在重新发明轮子;轮子是 interfaces/classes,通过在问题描述中引号之间使用 "interface" 来暗示重新发明 ;-)
我们没有被迫在所有地方使用 lambda。
虽然我发现 Tagir 的回答是一个很好的 hack,但在创建新的哈希器时很容易忘记添加私有常量。
像往常一样,在处理潜在的重构问题时,我认为测试是答案:
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));
}
}
Java 8 中是否有任何类似方法的 implements
关键字?
假设我有一个功能接口:
@FunctionalInterface
interface LongHasher {
int hash(long x);
}
和一个包含 3 个静态方法的库 "implementing" 这个功能接口:
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);
}
}
将来我希望能够互换使用对这 3 种方法的任何引用作为参数。例如:
static LongHashMap createHashMap(LongHasher hasher) { ... }
...
public static void main(String[] args) {
LongHashMap map = createHashMap(LongHashes::randomHash);
...
}
如何在编译时确保 LongHashes::xorHash
、LongHashes::continuingHash
和 LongHashes::randomHash
与 LongHasher.hash(long x)
具有相同的签名?
一种方法是直接从 LongHashes
class:
LongHasher
class LongHashes {
private static int xorHashImpl(long x) {
return (int)(x ^ (x >>> 32));
}
static LongHasher xorHash() {
return LongHashes::xorHashImpl;
}
}
但这会向您的 LongHashes
class 添加一些代码并将其绑定到 LongHasher
接口,这可能不是您所希望的(尽管这正是您所要求的)。
没有您要求的语法结构。但是,您可以创建一个静态常量,在其中显式地将方法引用分配给您的接口:
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);
}
}
这样,如果方法签名或接口以不兼容的方式更改,您的编译就会中断。如果你愿意,你可以声明它们 public
并使用而不是方法引用。
如果您关心这些静态 lambda 将在运行时挂在内存中,您可以将此声明移动到单独的 class(例如,嵌套),它编译但从不加载。
我过去也希望如此,但不,你不能那样做。但是你知道。 Java 之前有 Java 8. 改为:
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) { ... }
}
}
然后:
public static void main(String[] args) {
LongHashMap map = createHashMap(LongHashes.RANDOM);
...
}
您可以声明函数对象,而不是方法。
class LongHashes {
static final LongHasher xorHash = x -> {
return (int)(x ^ (x >>> 32));
};
... etc
LongHashMap map = createHashMap(LongHashes.randomHash);
或者只创建 3 个 类 来实现 LongHasher。当你需要一个 LongHasher 时,获取或创建一个实例并传递它:
LongHasher longHasher = ... // new RandomLongHasher(), factory, .......
LongHashMap map = createHashMap(longHasher);
这里把函数写成静态方法:
- 让人难以理解
- 听起来像是在重新发明轮子;轮子是 interfaces/classes,通过在问题描述中引号之间使用 "interface" 来暗示重新发明 ;-)
我们没有被迫在所有地方使用 lambda。
虽然我发现 Tagir 的回答是一个很好的 hack,但在创建新的哈希器时很容易忘记添加私有常量。
像往常一样,在处理潜在的重构问题时,我认为测试是答案:
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));
}
}