方法引用原始类型有害吗? [英] Method references to raw types harmful?

查看:218
本文介绍了方法引用原始类型有害吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码包含对 Enum :: name 的引用(请注意没有类型参数)。

The code below contains a reference to Enum::name (notice no type parameter).

public static <T extends Enum<T>> ColumnType<T, String> enumColumn(Class<T> klazz) {
    return simpleColumn((row, label) -> valueOf(klazz, row.getString(label)), Enum::name);
}

public static <T, R> ColumnType<T, R> simpleColumn(BiFunction<JsonObject, String, T> readFromJson,
        Function<T, R> writeToDb) {
 // ...
}

Javac在编译期间报告警告:

Javac reports a warning during compilation:


[警告]发现原始类型:java.lang.Enum缺少类型参数
泛型类java.lang.Enum

[WARNING] found raw type: java.lang.Enum missing type arguments for generic class java.lang.Enum

更改表达式到 Enum< T> :: name 导致警告消失。

Changing the expression to Enum<T>::name causes the warning to go away.

然而Idea标记 Enum< T> :: name 版本,警告:

However Idea flags the Enum<T>::name version with a warning that:


显式类型参数可以是推断

Explicit type arguments can be inferred

反过来,Eclipse(ECJ)不报告任何一个公式的任何问题。

In turn Eclipse (ECJ) doesn't report any problems with either formulation.

这三种方法中的哪一种是正确的?

一方面,原始类型相当令人讨厌。如果你试图放一些其他类型的参数,例如 Enum< Clause> :: name 将导致编译失败,因此它有一些额外的保护。

On one hand raw types are rather nasty. If you try to put some other type argument e.g. Enum<Clause>::name will cause the compilation to fails so it's some extra protection.

另一方面,上述参考文献相当于 e - > e.name() lambda,此公式不需要类型参数。

On the other hand the above reference is equivalent to e -> e.name() lambda, and this formulation doesn't require type arguments.

环境:


  • Java 8u91

  • IDEA 15.0.3社区

  • ECJ 4.5.2

推荐答案

没有原始方法参考这样的东西。虽然存在原始类型以帮助迁移前泛型代码,但是不存在任何预泛化的方法引用的使用,因此没有兼容模式并且类型推断是常态。 Java语言规范§15.13。方法参考表达式声明:

There is no such thing as a "raw method reference". Whilst raw types exist to help the migration of pre-Generics code, there can’t be any pre-Generics usage of method references, hence there is no "compatibility mode" and type inference is the norm. The Java Language Specification §15.13. Method Reference Expressions states:


如果方法或构造函数是通用的,则可以推断或明确提供相应的类型参数。类似地,方法引用表达式提到的泛型类型的类型参数可以显式提供或推断。

If a method or constructor is generic, the appropriate type arguments may either be inferred or provided explicitly. Similarly, the type arguments of a generic type mentioned by the method reference expression may be provided explicitly or inferred.

方法引用表达式总是多表达式

Method reference expressions are always poly expressions

所以你可以在 :: 之前调用类型,当它引用时为原始类型如果没有指定类型参数的泛型类,编译器仍将根据目标函数类型推断泛型类型签名。这就是为什么产生关于原始类型使用的警告在这里没有意义。

So while you may call the type before the :: a "raw type" when it referes to a generic class without specifying type arguments, the compiler will still infer the generic type signature according to the target function type. That’s why producing a warning about "raw type usage" makes no sense here.

请注意,例如

BiFunction<List<String>,Integer,String> f1 = List::get;
Function<Enum<Thread.State>,String> f2 = Enum::name;

可以使用 javac 编译而不会发出任何警告(规范命名类似的示例,其中类型应该被推断),而

can be compiled with javac without any warning (the specification names similar examples where the type should get inferred), whereas

Function<Thread.State,String> f3 = Enum::name;

生成警告。 规范说明关于此案例:

generates a warning. The specification says about this case:


在第二次搜索中,如果 P < sub> 1 ,..., P n 不为空且 P 1 ReferenceType 的子类型,然后将方法引用表达式视为具有类型的参数表达式的方法调用表达式 P 2 ,..., P n 。如果 ReferenceType 是原始类型,并且存在此类型的参数化, G< ...> ,那就是<的超类型code> P 1 ,要搜索的类型是应用于 G< ..的捕获转换(第5.1.10节)的结果。 。> ; ...

In the second search, if P1, ..., Pn is not empty and P1 is a subtype of ReferenceType, then the method reference expression is treated as if it were a method invocation expression with argument expressions of types P2, ..., Pn. If ReferenceType is a raw type, and there exists a parameterization of this type, G<...>, that is a supertype of P1, the type to search is the result of capture conversion (§5.1.10) applied to G<...>;…

所以在上面的例子中,编译器应推断枚举< Thread.State> 作为 Enum 的参数化,它是 Thread.State 搜索适当的方法,得到与 f2 示例相同的结果。它以某种方式 工作,但它会产生无意义的原始类型警告。

So in the above example, the compiler should infer Enum<Thread.State> as the parametrization of Enum that is a supertype of Thread.State to search for an appropriate method and come to the same result as for the f2 example. It somehow does work, though it generates the nonsensical raw type warning.

显然, javac 只有在必须搜索适当的超类型时才会生成此警告,您的案例有一个简单的解决方案。只需使用确切类型进行搜索:

Since apparently, javac only generates this warning when it has to search for an appropriate supertype, there is a simple solution for your case. Just use the exact type to search:

public static <T extends Enum<T>> ColumnType<T, String> enumColumn(Class<T> klazz) {
    return simpleColumn((row, label) -> valueOf(klazz, row.getString(label)), T::name);
}

此编译没有任何警告。

这篇关于方法引用原始类型有害吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆