使用方法引用和原始类型进行类型推断

Mar*_*cca 8 java generics type-inference

有没有办法告诉 Java 不要尝试从使用原始类型的方法引用推断类型?

这是我写的一个方法,这个原因现在无关紧要:

    public static <F, T> Predicate<F> isEquals(
            Function<F, T> aInMapFunction, T aInExpectedValue)
    {
        return aInActual -> Objects.equals(
                aInMapFunction.apply(aInActual), aInExpectedValue);
    }
Run Code Online (Sandbox Code Playgroud)

现在,如果您将方法引用传递给返回原始类型的“isEquals”会怎样?

Predicate<String> lLengthIs20 = isEquals(String::length, 20);
Run Code Online (Sandbox Code Playgroud)

这一切都很好,只是 Java 也会接受这种奇怪的用法:

Predicate<String> lLengthIs20 = isEquals(String::length, "what the heck?!?!?");
Run Code Online (Sandbox Code Playgroud)

这是因为编译器会将类型参数 T 推断为“ Serializable & Comparable<? extends Serializable & Comparable<?>>”,它将接受 Integer 和 String 类型。

在我的情况下,这是不可取的,因为我想要一个编译错误而不是 Java 找出一些疯狂的类型参数。就我而言,我还可以显式覆盖方法“isEquals”以采用特定的原始类型。例如:

    public static <F> Predicate<F> isEquals(
            ToIntFunction<F> aInMapFunction, int aInExpectedValue)
    {
        return aInActual ->
                aInMapFunction.applyAsInt(aInActual) == aInExpectedValue;
    }
Run Code Online (Sandbox Code Playgroud)

这工作正常,当我传入一个返回原始 int 的方法时,将调用此方法而不是 Object 方法。问题是我仍然需要 Object 方法,我无法删除它,这仍然会导致编译器接受我上面列出的奇怪调用。

所以问题是:当方法引用返回原始类型时,有没有办法告诉 Java 不要使用 isEquals 的对象版本?我找不到任何东西,我觉得我在这方面运气不佳。

(注意: isEquals 的对象版本的实际实现工作正常并且应该是安全的。这是因为 Object.equals 和 Object s .equals 接受 Object 参数,并且 String 对象永远不会等于 Integer 对象。然而,在语义上,这看起来很奇怪)

编辑:在“paranoidAndroid”发表评论之后,我的一个想法是按以下方式包装方法引用:

    public static <T> Function<T, Integer> wrap(ToIntFunction<T> aInFunction)
    {
        return aInFunction::applyAsInt;
    }
Run Code Online (Sandbox Code Playgroud)

现在,

Predicate<String> lLengthIs20 = isEquals(wrap(String::length), "what the heck?!?!?");
Run Code Online (Sandbox Code Playgroud)

... 产生编译错误。仍然不是很好,也许有更好的方法。至少这比显式传递类型要好,后者优于目的。

编辑 2:我现在在 Java 8 中。Java 11 在这里可能会有不同的表现,我没有测试。

编辑 3:我认为我们在这里无能为力,这只是对 Java 中类型推断如何工作的暗示。这是另一个例子:

    public static <T> boolean isEquals(T t1, T t2) {
        return Objects.equals(t1, t2);
    }
Run Code Online (Sandbox Code Playgroud)

使用此方法,以下表达式完全有效:

System.out.println(isEquals(10, "20"));
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为 Java 将尝试根据公共上限来解析 T 的类型。碰巧 Integer 和 String 共享相同的上限Serializable & Comparable<? extends Serializable & Comparable<?>>

ded*_*per 0

\n

\xe2\x80\x9e \xe2\x80\xa6有没有办法让我告诉Java不要使用对象版本\xe2\x80\xa6 \xe2\x80\x9c

\n
\n

是的。泛型 \xe2\x80\x94中用于告诉 Java 不要使用的术语 \xe2\x80\x94Object称为: \xe2\x80\ x9e\xe2\x80\x9c。

\n

我的实验证实,调用以下方法isEquals(String::hashCode, "What the theoretical fuck!&?*!?@!")将产生error: no suitable method found for isEquals(String::hashCode,String)......

\n
public static <F extends String, T extends Number> Predicate<F> isEquals(Function<F, T> aFunction, T aValue)\n{\n    return input -> Objects.equals(aFunction.apply(input), aValue);\n}  \n
Run Code Online (Sandbox Code Playgroud)\n

如果您在同一个类中同时拥有上述方法和以下方法,则调用此版本isEquals(String::length, 20)...

\n
public static <F> Predicate<F> isEquals(ToIntFunction<F> aFunction, int aValue)\n{\n    return input -> aFunction.applyAsInt(input) == aValue;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

...但是需要第一个isEquals(String::length, Integer.valueOf(42))

\n

单击此演示中的蓝色“执行”按钮以查看其工作情况。

\n