是否可以在不破坏 Java 的情况下向 Comparable 添加默认方法?

问题描述

我正在考虑提出一个功能请求来添加名为的方法

default boolean greaterThan(T o) {
    return compareto(o) > 0;
}

default boolean smallerThan(T o) {
    return compareto(o) < 0;
}

default boolean atLeast(T o) {
    return compareto(o) >= 0;
}

default boolean atMost(T o) {
    return compareto(o) <= 0;
}

Comparable 界面,因为它会使代码更具可读性 - 在我看来。

但是,我想知道这是否会破坏代码。如果我们添加方法,是否有任何诸如 Lambda 之类的代码会中断?

如果我正确阅读 this,我会假设 Lambda 至少会继续工作,只要它们不会尝试调用方法,但我不确定。而且我不知道是否有任何(明显的)其他问题。

请不要讨论可能的功能请求本身。

解决方法

不幸的是,@BasilBourque 的回答具有误导性,即使它引用了有用的实体。

无法通过子接口引入此功能。 SortedMap/NavigableMap 适用:当引入 default 时,NavigableMap 机制还没有出现!

此时,将 NavigableMap 中的部分或全部方法作为 default 中的 SortedMap 方法引入可能是值得的,其实现适用于 sortedmaps 并且会自动结束被任何已经实现 NavigableMap 的 Map impls 覆盖(因为它们已经覆盖了它们的 impl 中的所有那些)。

然而,这意味着“嘿,看看类似于 SortedMap 的 NavigableMap,就像你想对 Comparable 做的一样”是一个误导性的论点:你的提议涉及添加默认方法。那个时候还没有摆在桌面上。

最终您想要的是“几乎但不完全向后兼容”。 Oracle/Java Lang 架构师倾向于说“java 不会破坏向后兼容性”,但这是一种粗略的过度简化和边缘谎言。如果你问得更进一步,他们最终会承认这不是真的:问题的核心是 java 权衡任何向后中断的成本(它的可能性有多大,以及确实破坏它的代码会发生什么?如果它悄悄地仍然可以编译和运行但做错了事情,这太可怕了,如果这是一个重构脚本每次都可以自动应用的微不足道的更新,那就太好了 - 然后混合任何给定的代码库偶然发现它的可能性,你就有了一个想法'成本'),而不是它的好处。

这里的成本非常小。任何代码库都极不可能被破坏。然而,如果你想真正提出这个特性,做一些研究并尝试考虑任何库会很有帮助(或者如果你不能,看看各种人博客上的前 100 个列表,分析例如 github java 项目作为源材料)通过一堆尝试看看 .isEmpty 发生的事情是否会发生在这些方法中。

然后,有一些坏消息:提出一个 Java 特性极不可能成功。从某种角度来看,作为 Project Lombok 的作者,他花了数百个小时阅读 lambda-dev 等邮件列表,他贡献了大部分实际的 lambda 语法和概念基础,并与多个 Java 语言架构师进行了对话一些长度(主要是在 Java 会议上),我提交了一份提案,其中包括 Java 本身的完整补丁,以及 JLS 所需的所有应有更新,这根本没有破坏向后兼容性,而且它从未获得任何进展。甚至不如 JEP。

上次我与 Oracle 工程师交谈时,他们确实承诺现在情况会好一些,但这并没有特别远:我不知道周围或即将出现的任何 Java 功能是由在过去的 10 年里,一个直接被踢到 JEP 并接近可预见的 Java 特性范围的局外人。不时有人(通常是 Joe Darcy 或 Alex Buckley)运行一个项目来“添加一些方便的小语言更改”,例如 Project Coin(那是 11 年前的事了)。对此的第二个看法是 Project Amber,我认为它是一个更连续的项目,而不是具有特定短暂时间跨度的代币。

将其引入 java 的途径大概会经过 amber。

,

作为 commented by Johannes KuhnStuart Marks documented a caseCharSequence.isEmpty() 默认方法添加到 Java 15 破坏了第三方库。

因此,鉴于历史上优先考虑使用现有应用程序最大限度地 backward-compatible 开发新版本的 Java,更好的方法是定义一个新界面。新界面将介绍您的新方法。理论上,在很长一段时间后,旧界面最终可能会被标记为已弃用,以建议为新界面逐步淘汰旧界面。同时,现有代码不会受到干扰,而新代码可以利用新想法。

例如,这是在 Map 界面中完成的。子接口 SortedMap 随 Java 1.2(又名 Java 2)一起出现。多年后,在 Java 6 中,出现了使用其他方法扩展该接口的想法。但是修改 SortedMap 存在干扰捆绑 Java 库中现有实现以及破坏第三方实现的风险。所以他们选择定义一个新的接口 NavigableMap。他们将较新的接口 NavigableMap 作为 SortedMap 的子接口。

NavigableMap 实际上只是 SortedMap 的“2.0”版本。据我所知,没有任何实现不希望支持更大的方法套件而不是 SortedMap 中发现的更少的方法。所以,当然,最好只有一个这样的界面而不是两个,但是c'est la vie

这是我制作的图表,显示了与 Java 11 捆绑在一起的 Map 接口的各种实现。您可以看到接口 SortedMapNavigableMap 如何并排存在.

Table of map implementations in Java 11,comparing their features

我全心全意支持您使用这些特定方法有效扩展 Comparable 的想法(顺便说一句,好的命名也是如此)。但我相信你的提议只会作为 Comparable 的新子接口。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...