Java 8 默认方法会破坏源代码兼容性吗? [英] Do Java 8 default methods break source compatibility?

查看:26
本文介绍了Java 8 默认方法会破坏源代码兼容性吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java 源代码通常是向前兼容的.据我所知,在 Java 8 之前,编译类 源代码都向前兼容以后的 JDK/JVM 版本.[更新:这不正确,请参阅下面的枚举"等注释.] 然而,随着 Java 8 中默认方法的添加,情况似乎不再如此.

例如,我一直在使用的库有一个 java.util.List 的实现,其中包括一个 List排序().此方法返回已排序的列表内容的副本.该库作为 jar 文件依赖项部署,在使用 JDK 1.8 构建的项目中运行良好.

但是,后来我有机会使用 JDK 1.8 重新编译库本身,并且我发现库不再编译:带有自己的 sort() 方法的 List 实现类现在与 Java 8 java.util.List.sort 冲突() 默认方法.Java 8 sort() 默认方法对列表进行原地排序(返回 void);我的库的 sort() 方法 - 因为它返回一个新的排序列表 - 具有不兼容的签名.

所以我的基本问题是:

  • JDK 1.8 是否会因为默认方法而导致 Java 源代码向前不兼容?

还有:

  • 这是第一个此类向前不兼容的更改吗?
  • 在设计和实施默认方法时是否考虑或讨论了这一点?是否记录在任何地方?
  • (无可否认的)不便与好处相比是否打折扣?

以下是一些在1.7下编译运行的代码示例,在 1.8 下运行 - 但不能在 1.8 下编译:

import java.util.*;公共最终类 Sort8 {公共静态无效主(字符串 [] args){SortableListl = new SortableList(Arrays.asList(args));System.out.println("未排序:"+l);SortableLists = l.sort(Collections.reverseOrder());System.out.println("排序:"+s);}公共静态类 SortableList扩展 ArrayList{公共 SortableList() { super();}public SortableList(Collection col) { super(col);}公共 SortableList排序(比较器 cmp){SortableListl = new SortableList();l.addAll(this);Collections.sort(l, cmp);返回 l;}}}

以下显示了此代码正在编译(或无法)并正在运行.

>c:	oolsjdk1.7.0_10injavac Sort8.java>c:	oolsjdk1.7.0_10injava Sort8 这是一个测试未分类:[this, is, a, test]排序:[这个,测试,是,一个]>c:	oolsjdk1.8.0_05injava Sort8 这是一个测试未分类:[this, is, a, test]排序:[这个,测试,是,一个]>del Sort8*.class>c:	oolsjdk1.8.0_05injavac Sort8.javaSort8.java:46: 错误:SortableList 中的 sort(Comparator) 无法在 List 中实现 sort(Comparator)公共 SortableList排序(比较器 cmp){^返回类型 SortableList与 void 不兼容其中 V,E 是类型变量:V 扩展类 SortableList 中声明的对象E 扩展接口 List 中声明的对象1 错误

解决方案

JDK 1.8 不是因为默认方法引入了 Java 源代码的向前不兼容吗?

超类或接口中的任何新方法都可能破坏兼容性.默认方法使不太可能接口的更改会破坏兼容性.从某种意义上说,默认方法为向接口添加方法打开了大门,您可以说默认方法可能会导致兼容性受损.

这是第一个向前不兼容的更改吗?

几乎肯定不是,因为我们从 Java 1.0 开始就从标准库中继承类.

在设计和实施默认方法时是否考虑或讨论了这一点?是否记录在任何地方?

是的,它被考虑过.参见 Brian Goetz 于 2010 年 8 月发表的论文 通过公共辩护人"方法进行的界面演变":

<块引用>

  1. 源兼容性

此方案可能会引入源代码不兼容性,以至于修改库接口以插入与现有类中的方法不兼容的新方法.(例如,如果一个类有一个浮点值的 xyz() 方法并实现了 Collection,而我们在 Collection 中添加了一个 int 值的 xyz() 方法,则现有的类将不再编译.)

(无可否认的)不便与好处相比是否打折扣了?

以前,更改接口肯定会破坏兼容性.现在,它可能.从肯定"到可能"可以看到积极或消极的一面.一方面,它使得向接口添加方法成为可能.另一方面,它为您所看到的那种不兼容打开了大门,不仅是类,还有接口.

不过,正如 Goetz 论文开头所述:

<块引用>

  1. 问题说明

一旦发布,就不可能在不破坏现有实现的情况下向接口添加方法.一个库发布的时间越长,这个限制就越有可能给它的维护者带来悲伤.

在 JDK 7 中向 Java 语言添加闭包给老化的 Collection 接口带来了额外的压力;闭包最重要的好处之一是它可以开发更强大的库.添加一种语言功能来启用更好的库,同时不扩展核心库以利用该功能,这将是令人失望的.

It has generally been the case the Java source code has been forward compatible. Until Java 8, as far as I know, both compiled classes and source have been forward compatible with later JDK/JVM releases. [Update: this is not correct, see comments re 'enum', etc, below.] However, with the addition of default methods in Java 8 this appears to no longer be the case.

For example, a library I have been using has an implementation of java.util.List which includes a List<V> sort(). This method returns a copy of the contents of the list sorted. This library, deployed as a jar file dependency, worked fine in a project being built using JDK 1.8.

However, later I had occasion to recompile the library itself using JDK 1.8 and I found the library no longer compiles: the List-implementing class with its own sort() method now conflicts with the Java 8 java.util.List.sort() default method. The Java 8 sort() default method sorts the list in place (returns void); my library's sort() method - since it returns a new sorted list - has an incompatible signature.

So my basic question is:

  • Doesn't JDK 1.8 introduce a forward incompatibility for Java source code due to default methods?

Also:

  • Is this the first such forward incompatible change?
  • Was this considered or discussed when default methods where designed and implemented? Is it documented anywhere?
  • Was the (admittedly small) inconvenience discounted versus the benefits?

The following is an example of some code that compiles and runs under 1.7 and runs under 1.8 - but does not compile under 1.8:

import java.util.*;

public final class Sort8 {

    public static void main(String[] args) {
        SortableList<String> l = new SortableList<String>(Arrays.asList(args));
        System.out.println("unsorted: "+l);
        SortableList<String> s = l.sort(Collections.reverseOrder());
        System.out.println("sorted  : "+s);
    }

    public static class SortableList<V> extends ArrayList<V> {

        public SortableList() { super(); }
        public SortableList(Collection<? extends V> col) { super(col); }

        public SortableList<V> sort(Comparator<? super V> cmp) {
            SortableList<V> l = new SortableList<V>();
            l.addAll(this);
            Collections.sort(l, cmp);
            return l;
        }

    }

}

The following shows this code being compiled (or failing to) and being run.

> c:	oolsjdk1.7.0_10injavac Sort8.java

> c:	oolsjdk1.7.0_10injava Sort8 this is a test
unsorted: [this, is, a, test]
sorted  : [this, test, is, a]

> c:	oolsjdk1.8.0_05injava Sort8 this is a test
unsorted: [this, is, a, test]
sorted  : [this, test, is, a]

> del Sort8*.class

> c:	oolsjdk1.8.0_05injavac Sort8.java
Sort8.java:46: error: sort(Comparator<? super V>) in SortableList cannot implement sort(Comparator<? super E>) in List
                public SortableList<V> sort(Comparator<? super V> cmp) {
                                       ^
  return type SortableList<V> is not compatible with void
  where V,E are type-variables:
    V extends Object declared in class SortableList
    E extends Object declared in interface List
1 error

解决方案

Doesn't JDK 1.8 introduce a forward incompatibility for Java source code due to default methods?

Any new method in a superclass or interface can break compatibility. Default methods make it less likely that a change in an interface will break compatibility. In the sense that default methods open the door to adding methods to interfaces, you could say that default methods may contribute to some broken compatibility.

Is this the first such forward incompatible change?

Almost certainly not, since we've been subclassing classes from the standard library since Java 1.0.

Was this considered or discussed when default methods were designed and implemented? Is it documented anywhere?

Yes, it was considered. See Brian Goetz's August 2010 paper "Interface evolution via "public defender" methods":

  1. Source compatibility

It is possible that this scheme could introduce source incompatibilities to the extent that library interfaces are modified to insert new methods that are incompatible with methods in existing classes. (For example, if a class has a float-valued xyz() method and implements Collection, and we add an int-valued xyz() method to Collection, the existing class will no longer compile.)

Was the (admittedly small) inconvenience discounted versus the benefits?

Before, changing an interface would definitely break compatibility. Now, it might. Going from 'definitely' to 'might' can be seen either positively or negatively. On the one hand, it makes it feasible to add methods to interfaces. On the other hand, it opens the door to the kind of incompatibility you saw, not just with classes, but with interfaces too.

The benefits are larger than the inconveniences, though, as cited at the top of Goetz's paper:

  1. Problem statement

Once published, it is impossible to add methods to an interface without breaking existing implementations. The longer the time since a library has been published, the more likely it is that this restriction will cause grief for its maintainers.

The addition of closures to the Java language in JDK 7 place additional stress on the aging Collection interfaces; one of the most significant benefits of closures is that it enables the development of more powerful libraries. It would be disappointing to add a language feature that enables better libraries while at the same time not extending the core libraries to take advantage of that feature.

这篇关于Java 8 默认方法会破坏源代码兼容性吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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