简体   繁体   English

如何在Java 8编译时确保方法签名“实现”功能接口

[英]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::xorHashLongHashes::continuingHash LongHashes::randomHashLongHashes::randomHashLongHasher.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: 在这里编写静态方法的函数:

  • makes it difficult to understand 让人难以理解
  • sounds like reinventing the wheel; 听起来像重新发明轮子; the wheel being interfaces/classes, reinventing being hinted by the use of "interface" between quotes in the problem description ;-) 轮子是接口/类,通过在问题描述中引用之间使用“接口”重新发明暗示;-)

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.

相关问题 如何确保参数实现接口 - How to ensure an argument implements an interface 是否可以让方法签名成为它实现的接口的子类型? - Is it possible to have a method signature be a subtype of the interface it implements? Java 使用泛型参数和默认方法实现编译功能接口失败 - Java failed to compile Functional Interface with generic parameter and default method implementation 如果我在实现该接口的方法中抛出异常,我怎么能不在接口方法签名处抛出异常? - How can I not throw exception at interface method signature If I throw exception in method that implements that interface? 方法参考的通用功能接口的方法签名 - Method signature of generic Functional Interface of Method References Java:如何调用在接口中实现另一个方法的方法? - Java: How do I call a method that implements another method in an interface? 通过功能接口方法签名获取 class 构造函数 - Get class constructor by functional interface method signature 如何使用课堂 <Interface> Java中的方法签名 - How to use Class<Interface> in method signature in Java Java:如何确保接口方法不比X花费更多时间? - Java: how to ensure an interface method doesn't take more time than X? 如何使用MethodHandles在实现Java 8接口的类上调用方法? - How to use MethodHandles to call a method on the class that implements an interface in Java 8?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM