Javaが型推論を行わないのはなぜですか?


44

私はいつも、Javaが言語であり、そのVMが非常に成熟していることを考えると、Javaが型推論を行わない理由を常に疑問に思っていました。GoogleのGoは、優れた型推論を備えた言語の例であり、必要な入力の量を減らします。この機能がJavaの一部ではない背後に特別な理由はありますか?


3
Javaと同じくらい古く人気のある言語での後方互換性ルール
ラチェットフリーク

9
@ratchetfreak型推論は後方互換性のある方法で追加できませんでしたか?古いプログラムは、必要以上の型情報を提供するだけです。

1
Type Erasureで使用すると、意図しない効果が生じる場合があります。docs.oracle.com/javase/tutorial/java/generics/...
ザカリーイエーツ

4
Java 8はLambda機能を使用して多くの型推論を行うことに注意してください。型や推論されるすべてに言及することなく、複雑なラムダを記述できます。
ヨアヒムザウアー

4
Javaにローカル変数型の推論がやってくる:JEP 286:Local-Variable Type Inference
Jimmy Page

回答:


60

技術的に言えば、ジェネリックを使用する場合、Javaには型推論があります。のような一般的な方法で

public <T> T foo(T t) {
  return t;
}

コンパイラは、あなたが書くとき、それを分析して理解します

// String
foo("bar");
// Integer
foo(new Integer(42));

引数として入力されたものに基づいて、最初の呼び出しでは文字列が返され、2番目の呼び出しでは整数が返されます。その結果、適切なコンパイル時チェックが行われます。さらに、Java 7では、次のようなジェネリックをインスタンス化するときに、追加の型推論を取得できます。

Map<String, String> foo = new HashMap<>();

Javaは、私たちにとって空白の山括弧を埋めるのに十分なほど親切です。なぜJava は変数の割り当ての一部として型推論をサポートしないのですか?ある時点で、変数宣言に型推論のRFEがありましたが、これは「修正しない」として閉じられました。

人間は、2つの方法で型宣言の冗長性の恩恵を受けます。まず、冗長な型は貴重なドキュメントとして機能します。読者はgetMap()の宣言を検索して、返される型を見つける必要はありません。第二に、冗長性により、プログラマは目的の型を宣言できるため、コンパイラによって実行されるクロスチェックの利点が得られます。

これを閉じた寄稿者は、「javaに似ていない」ように感じていることにも気付きました。Javaの冗長性は、祝福と呪いの両方になりますが、言語をそのままにします。

もちろん、その特定のRFEはその会話の終わりではありませんでした。Java 7では、この機能が再び検討され、James Gosling自身によるものなど、いくつかのテスト実装が作成されました。繰り返しますが、この機能は最終的に打ち切られました。

Java 8のリリースにより、ラムダの一部として型推論が取得されるようになりました。

List<String> names = Arrays.asList("Tom", "Dick", "Harry");
Collections.sort(names, (first, second) -> first.compareTo(second));

Javaコンパイラは、メソッドを見することができCollections#sort(List<T>, Comparator<? super T>)、その後のインタフェースComparator#compare(T o1, T o2)とすることを決定firstし、secondなければならないString、したがって、プログラマは、ラムダ式でタイプを修正再表示すること差し控えることを可能にします。


5
First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns-はい、そうであればHashMap<String, Integer> map = foo.getMap()私は同意します-C#ではvar、私はできても、そのような場合には通常使用しません。それはだ場合でも、この引数には、水を保持していませんHashMap<String, Integer> map = new HashMap<String, Integer>()。これは真の冗長性であり、タイプ名を2回記述する必要があるという利点はありません。そして、ここでコンパイラーのクロスチェックからどのように恩恵を受けるのか、私にはまったくわかりません。
コンラッドモラウスキ14年

9
はい、それはジェネリックには適していますがvar、Java のC#に相当するものがまだありません。
コンラッドモラウスキー14年

15
「非Javaに似」のためとして、それは、この(安っぽい)話が頭に浮かぶされている;)9gag.com/gag/2308699/-this-is-how-things-are-done-around-here
コンラートMorawski

6
さらに、関数の戻り値の型は多くの場合明白または不要であり、IDEがそうでない場合でも0.5秒で型にフラグを立てることができます。
Phoshi

8
Humans benefit from the redundancyが読んだすべての正当化は、Javaデザイナーからの根拠のない根拠のないばかげた言い訳のようだからです: Java、そして誰もがそれを使って満足しています。Java開発者がC#やC ++開発者と異なる原因は何ですか?これが、@ KonradMorawskiに同意する理由です。「これがここでのやり方です」が再びその背後にある本当の理由であるようです。
paercebal

16

まあ、最初に、型推論はランタイムの成熟度とは何の関係もありません。ランタイムが30年前のCPUであってもVMであっても、ビットはまだ輝いています。コンパイラーがすべてです。

とはいえ、ジェネリックは許可されていますが、非ジェネリック型が許可されない理由は、哲学のためであるようです-デザイナーがそれを追加することを妨げるものは何もありません。

更新:java 10がサポートしているように見える-http: //openjdk.java.net/jeps/286


5

私の知る限り、90年代の初めにJavaが設計されたとき、型推論は主流の言語の間ではそれほど一般的ではありませんでした(ただし、MLなどではすでによく知られた概念でした)。そのため、JavaはC ++、Pascal、またはそれを持たない他の主流言語のプログラマーを対象としていたため、型推論はおそらくサポートされていなかったと想像できます(原則としては驚くべきことではありません)。

また、Javaの設計原則の1つは、プログラマーとコンパイラーがコードを同じように理解できるように明示的に記述することです。情報を複製することでエラーの可能性を減らします。もちろん、いくつかの文字をさらに入力することが安全性に見合うだけの価値があるかどうかは好みの問題かもしれませんが、これはJavaの設計哲学でした。

Javaが将来型推論を取得するかどうかはわかりませんが、IMOはこの言語にとって大きな革命になるでしょう(グレンネルソンが言及したように、「un-javaのような」と言われました)。 Javaに新しい名前を付けてください。

型推論でJVM言語を使用する場合は、Scalaを使用できます。


2

いくつかの理由が考えられます。1つは、明示的な型指定は自己文書化であるということです。Javaは通常、これを簡潔さよりも優先します。もう1つの理由は、型が多少あいまいな場合です。タイプまたはサブタイプがルーチンを満たす場合のように。リストを使用したいが、誰かがやって来て、ArrayList専用のメソッドを使用するとします。JITはArrayListを推測し、コンパイルエラーが必要な場合でも続行します。


8
GridBagLayout gridbag = new GridBagLayout();の仕組み 自己文書に追加しますか?その純粋な繰り返し。
アンデルスリンデン

3
2つのタイプが同じではない場合と区別されます。サブクラスのインスタンスを簡単に割り当てることができます。
ジギー

Let's say you want to use a List, but someone comes along and uses a method exclusive to ArrayList. The JIT would infer an ArrayList and carry on even if you wanted a compilation error-私はこのビットを理解していません。型の推論は、変数のメソッドを呼び出すのではなく、変数のインスタンス化の瞬間に行われます。おそらくあなたが何を意味するのか例を示していただけますか?
コンラッドモラウスキ14年

2
@KonradMorawski:私は、メソッドがArrayListを返す場合、型はそれに推論されることを意味すると思います。型を戻り型以外のものとして扱いたい場合は、推論を使用できません。しかし、これが正気に近いコードベースでどのように問題になるかはわかりません。
フォシ14年

JITは型推論にまったく関与しません。型推論はコンパイル時の現象です。また、変数がリストへの参照として宣言されている場合、その変数のArrayListメンバーにアクセスしようとすると、チェックが入力されず、コンパイルエラーが発生します
sara

0

これは、ニーズに合う最も一般的なインターフェイスを使用して変数を宣言し、次のように適切な実装クラスで初期化するという確立された推奨事項と矛盾します

Collection<String> names = new ArrayList<>();

事実上、

var names = new ArrayList<String>();

のための構文糖に過ぎない

ArrayList<String> names = new ArrayList<String>();

必要に応じて、IDEはnew ArrayList<String>()「ワンクリック」式(リファクタリング/ローカル変数の作成)で式から生成できますが、「インターフェイスの使用」の推奨事項と矛盾することに注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.