java - Collections.max() 签名的实际使用

标签 java generics wildcard

这是对 Explanation of Collections.max() signature 的后续问题,其中接受的答案没有深入探讨此通配符的实际原因。

max方法需要一个 Collection<? extends T>我想不出这个通配符有帮助的实际案例。

我什至提到了Oracle More fun with wildcards它指出

In general, if you have an API that only uses a type parameter T as an argument, its uses should take advantage of lower bounded wildcards (? super T). Conversely, if the API only returns T, you'll give your clients more flexibility by using upper bounded wildcards (? extends T).

但是我还是没看懂。连Java Generics and Collections书中并没有过多讲述这个通配符背后的原因。

这个有实际用途吗?真实世界的用例会很棒。

最佳答案

想象一下这两个签名:

static <T extends Object & Comparable<? super T>> T max1(Collection<T> coll);
static <T extends Object & Comparable<? super T>> T max2(Collection<? extends T> coll);

现在,让我们尝试构造类型函数。

Function<Collection<java.sql.Timestamp>, java.util.Date>

// This doesn't work:
Function<Collection<Timestamp>, Date> f0 = 
    (Collection<Timestamp> col) -> Test.<Date>max1(col);

// This works:
Function<Collection<Timestamp>, Date> f1 = 
    (Collection<Timestamp> col) -> Test.<Date>max2(col);

如您所见,使用显式键入,其中一种方法不再有效。

类型推断在“现实世界”中“隐藏”了这个问题:

当然,您可以省略泛型类型参数的显式绑定(bind) Test.<Date>maxN() :

Function<Collection<Timestamp>, Date> f0 = 
    (Collection<Timestamp> col) -> Test.max1(col);
Function<Collection<Timestamp>, Date> f1 = 
    (Collection<Timestamp> col) -> Test.max2(col);

甚至:

Function<Collection<Timestamp>, Date> f2 = Test::max1;
Function<Collection<Timestamp>, Date> f3 = Test::max2;

并且类型推断会发挥它的魔力,因为上面所有的编译。

现在何必呢?

我们应该始终关心 API 的一致性,因为 pbabcdefp has said in his answer .想象一下还有一个额外的 optionalMax()方法(只是为了处理空参数集合的情况):

static <T extends ...> Optional<T> optionalMax1(Collection<T> coll);
static <T extends ...> Optional<T> optionalMax2(Collection<? extends T> coll);

现在,您可以清楚地看到只有第二种变体有用:

// Does not work:
Function<Collection<Timestamp>, Optional<Date>> f0 = 
    (Collection<Timestamp> col) -> Test.optionalMax1(col);
Function<Collection<Timestamp>, Optional<Date>> f2 = Test::max1;

// Works:
Function<Collection<Timestamp>, Optional<Date>> f1 = 
    (Collection<Timestamp> col) -> Test.optionalMax2(col);
Function<Collection<Timestamp>, Optional<Date>> f3 = Test::optionalMax2;

考虑到这一点,以下 API 会感觉非常不一致,因此是错误的:

static <T extends ...> T max(Collection<T> coll);
static <T extends ...> Optional<T> optionalMax(Collection<? extends T> coll);

因此,为了保持一致(无论是否需要输入),方法应该使用Collection<? extends T>签名。总是。

关于java - Collections.max() 签名的实际使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30012669/

相关文章:

java - Eureka客户端无法向eureka服务器注册服务

具有复合键和通配符的 Java 泛型

Java 正则表达式不匹配?

java - 在 [game.Game] 类型的 bean 中找不到有关属性 [bankOffer] 的任何信息

c# - 从通用存储库返回动态列表

c# - 使用其他人共有的方法实现通用 C# 类

c# - 使用 AsCacheQueryable 和通用查询性能高效地从 Ignite 获取数据

doctrine-orm - 学说2 dql,在进行类似比较时使用带有%通配符的setParameter

java - elasticsearch 6.1.2 中不区分大小写的搜索

java - 返回存在字母的字符串的总和 - 使用流