web-dev-qa-db-ja.com

Java 8つのデフォルトのメソッドはソースの互換性を壊しますか?

通常、Javaソースコードには上位互換性があります。 Java 8までは、私の知る限り、コンパイルされたクラスの両方のソースは、以降のJDK/JVMリリースと上位互換性があります。 [更新:これは正しくありません。以下の「列挙型」などのコメントを参照してください。]ただし、Java 8にデフォルトのメソッドが追加されたため、これは当てはまらないようです。

たとえば、私が使用していたライブラリには、List<V> sort()を含む_Java.util.List_の実装があります。このメソッドは、ソートされたリストの内容のコピーを返します。このライブラリは、jarファイルの依存関係としてデプロイされ、JDK 1.8を使用してビルドされているプロジェクトで正常に機能しました。

しかし、後でJDK 1.8を使用してライブラリ自体を再コンパイルする機会があり、ライブラリがコンパイルされなくなったことがわかりました。独自のsort()メソッドを含むList- implementingクラスがJava 8 Java.util.List.sort()デフォルトメソッド。 Java 8 sort() defaultメソッドは、リストを所定の場所に並べ替えます(voidを返します)。私のライブラリのsort()メソッド-新しいソートされたリストを返すため、互換性のないシグネチャがあります。

だから私の基本的な質問は:

  • JDK 1.8では、デフォルトのメソッドが原因で、Javaソースコードに前方非互換性が導入されていませんか?

また:

  • これは、このような前方互換性のない最初の変更ですか?
  • デフォルトの方法が設計および実装されたときに、これは考慮または議論されましたか?どこに文書化されていますか?
  • (確かに小さい)不便さはメリットと比較して割り引かれましたか?

以下は、1.7でコンパイルおよび実行され、1.8で実行されるが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;
        }

    }

}
_

以下は、このコードがコンパイルされている(または失敗している)と実行されていることを示しています。

_> c:\tools\jdk1.7.0_10\bin\javac Sort8.Java

> c:\tools\jdk1.7.0_10\bin\Java Sort8 this is a test
unsorted: [this, is, a, test]
sorted  : [this, test, is, a]

> c:\tools\jdk1.8.0_05\bin\Java Sort8 this is a test
unsorted: [this, is, a, test]
sorted  : [this, test, is, a]

> del Sort8*.class

> c:\tools\jdk1.8.0_05\bin\javac 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
_
54
Paul

JDK 1.8は、Javaデフォルトのメソッドによるソースコード)の前方互換性を導入していませんか?

スーパークラスまたはインターフェースの新しいメソッドは、互換性を損なう可能性があります。デフォルトのメソッドはそれを可能にします可能性は低いインターフェースの変更が互換性を壊すであろうこと。デフォルトのメソッドは、インターフェースにメソッドを追加するための扉を開くという意味で、デフォルトのメソッドは互換性の破壊に寄与していると言えます。

これは、このような前方互換性のない最初の変更ですか?

Java 1.0。以来、標準ライブラリのクラスをサブクラス化しているので、ほぼ間違いなくそうです。

これは、デフォルトのメソッドが設計および実装されたときに考慮または議論されましたか?どこに記載されていますか?

はい、考慮されました。ブライアンゲッツの2010年8月の論文を参照してください "" public defender "メソッドによるインターフェースの進化"

  1. ソースの互換性

このスキームは、既存のクラスのメソッドと互換性のない新しいメソッドを挿入するためにライブラリインターフェースが変更される範囲で、ソースの非互換性を導入する可能性があります。 (たとえば、クラスにfloat値のxyz()メソッドがあり、Collectionを実装し、int値のxyz()メソッドをCollectionに追加すると、既存のクラスはコンパイルされなくなります。)

(明らかに小さい)不便さはメリットと比較して割り引きされましたか?

以前は、インターフェイスを変更すると間違いなく互換性が失われました。さて、それはmightです。 「間違いなく」から「可能性」への移行は、肯定的にも否定的にも見ることができます。一方では、インターフェースにメソッドを追加することが可能になります。一方、これは、クラスだけでなく、インターフェースにも見られるような非互換性への扉を開きます。

しかし、ゲッツの論文の冒頭で引用したように、利点は不便さよりも大きい:

  1. 問題文

いったん公開されると、既存の実装を壊さずにメソッドをインターフェースに追加することは不可能です。ライブラリが公開されてからの時間が長いほど、この制限によってメンテナに悲しみが生じる可能性が高くなります。

JDK 7のJava言語にクロージャーを追加すると、エージングコレクションインターフェースに追加のストレスがかかります。クロージャーの最も重要な利点の1つは、より強力なライブラリの開発が可能になることです。より優れたライブラリを可能にすると同時に、コアライブラリを拡張してその機能を利用しない言語機能を追加するのはがっかりすることです。

57
Andy Thomas

JDK 1.8は、Javaのデフォルトのメソッドによるソースコードの非互換性を導入していませんか?

はい、あなた自身を見てきました。

これは、このような前方互換性のない最初の変更ですか?

いいえ。Java 5 enumkeywordも壊れていました。その前に、Java 5 +

デフォルトの方法が設計および実装されたときに、これは考慮または議論されましたか?どこに文書化されていますか?

はい Orcale Java 8ソース非互換性の説明

(確かに小さい)不便さはメリットと比較して割り引かれましたか?

はい

9
dkatzel

抽象クラスでパラレルを描画できます。抽象クラスは、抽象メソッドを実装できるようにサブクラス化することを目的としています。抽象クラス自体には、抽象メソッドを呼び出す具象メソッドが含まれています。抽象クラスは、より具体的なメソッドを追加することで自由に進化できます。そしてこの慣習はサブクラスを壊すかもしれません。

したがって、あなたが説明した正確な問題は、Java8以前でも存在していました。実際には多くのサブクラスが出回っているので、問題はコレクションAPIでより明確になります。

デフォルトメソッドの主な動機は、サブクラスを壊すことなく既存のコレクションAPIにいくつかの有用なメソッドを追加することでしたが、サブクラスを壊すことを恐れて、それをやり過ぎるという大きな自己制御を行わなければなりませんでした。デフォルトのメソッドは、どうしても必要な場合にのみ追加されます。ここで本当の質問は、なぜList.sortは絶対に必要であると考えられています。それは議論の余地があると思います。

デフォルトのメソッドが最初に導入された理由に関係なく、これはAPIデザイナーにとって優れたツールになりました。抽象クラスの具象メソッドと同じように扱う必要があります。これらは事前に注意深く設計する必要があります。新しいものは慎重に導入する必要があります。

3
ZhongYu

皮肉なことに、インターフェイスにデフォルトのメソッドが導入され、それらのインターフェイスを使用する既存のライブラリnotが壊れるのを許容する一方で、インターフェイスに大規模なnew機能が導入されました。 (下位互換性。)

そのsortメソッドのような競合が発生する可能性があります。追加機能のために支払うもの。あなたの場合も調査する必要があります(代わりに新しい機能を使用する必要がありますか?)。

Javaの上位互換性の中断はほとんどなく、タイピングシステムではさらに大きくなりました。最初にジェネリック型を使用し、次に関数型インターフェイスから推定された型を使用します。バージョン間およびコンパイラー間でわずかな違いがありました。

2
Joop Eggen

この問題を読んで、私はその解決策を考えていました。
デフォルトのメソッドは後方互換性の問題を解決しましたが、前方互換性の問題が存在します。
既存のクラスを拡張する代わりに、そのような場合は、アプリケーション固有のインターフェースを使用して、クラスにいくつかの望ましい動作を追加できると思います。このアプリケーション固有のインターフェースを実装して使用できます。

0
pfulara