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

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

问题描述

下面的代码包含对 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::name 会导致警告消失.

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

然而,Idea 用警告标记了 Enum::name 版本:

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

可以推断显式类型参数

反过来,Eclipse (ECJ) 没有报告任何一种配方有任何问题.

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

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

一方面,原始类型相当讨厌.如果您尝试放置一些其他类型的参数,例如Enum::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

推荐答案

没有原始方法引用"这样的东西.虽然原始类型的存在是为了帮助迁移 pre-Generics 代码,但不能有任何 pre-Generics 使用方法引用,因此没有兼容模式",类型推断是常态.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.

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

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:

在第二次搜索中,如果P1, ..., Pn 不为空且P1ReferenceType 的子类型,那么方法引用表达式就被当作一个方法调用表达式,参数表达式类型为 <代码>P2, ..., Pn.如果 ReferenceType 是一个原始类型,并且存在这个类型的参数化,G<...>,它是 P 的超类型1,要搜索的类型是应用于G<...>;...

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<...>;…

所以在上面的例子中,编译器应该将 Enum 推断为 Enum 的参数化,它是 Thread.State<的超类型/code> 来搜索合适的方法并得到与 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天全站免登陆