私はいつも、Javaが言語であり、そのVMが非常に成熟していることを考えると、Javaが型推論を行わない理由を常に疑問に思っていました。GoogleのGoは、優れた型推論を備えた言語の例であり、必要な入力の量を減らします。この機能がJavaの一部ではない背後に特別な理由はありますか?
私はいつも、Javaが言語であり、そのVMが非常に成熟していることを考えると、Javaが型推論を行わない理由を常に疑問に思っていました。GoogleのGoは、優れた型推論を備えた言語の例であり、必要な入力の量を減らします。この機能がJavaの一部ではない背後に特別な理由はありますか?
回答:
技術的に言えば、ジェネリックを使用する場合、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
、したがって、プログラマは、ラムダ式でタイプを修正再表示すること差し控えることを可能にします。
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回記述する必要があるという利点はありません。そして、ここでコンパイラーのクロスチェックからどのように恩恵を受けるのか、私にはまったくわかりません。
var
、Java のC#に相当するものがまだありません。
Humans benefit from the redundancy
が読んだすべての正当化は、Javaデザイナーからの根拠のない根拠のないばかげた言い訳のようだからです: Java、そして誰もがそれを使って満足しています。Java開発者がC#やC ++開発者と異なる原因は何ですか?これが、@ KonradMorawskiに同意する理由です。「これがここでのやり方です」が再びその背後にある本当の理由であるようです。
まあ、最初に、型推論はランタイムの成熟度とは何の関係もありません。ランタイムが30年前のCPUであってもVMであっても、ビットはまだ輝いています。コンパイラーがすべてです。
とはいえ、ジェネリックは許可されていますが、非ジェネリック型が許可されない理由は、哲学のためであるようです-デザイナーがそれを追加することを妨げるものは何もありません。
更新:java 10がサポートしているように見える-http: //openjdk.java.net/jeps/286
私の知る限り、90年代の初めにJavaが設計されたとき、型推論は主流の言語の間ではそれほど一般的ではありませんでした(ただし、MLなどではすでによく知られた概念でした)。そのため、JavaはC ++、Pascal、またはそれを持たない他の主流言語のプログラマーを対象としていたため、型推論はおそらくサポートされていなかったと想像できます(原則としては驚くべきことではありません)。
また、Javaの設計原則の1つは、プログラマーとコンパイラーがコードを同じように理解できるように明示的に記述することです。情報を複製することでエラーの可能性を減らします。もちろん、いくつかの文字をさらに入力することが安全性に見合うだけの価値があるかどうかは好みの問題かもしれませんが、これはJavaの設計哲学でした。
Javaが将来型推論を取得するかどうかはわかりませんが、IMOはこの言語にとって大きな革命になるでしょう(グレンネルソンが言及したように、「un-javaのような」と言われました)。 Javaに新しい名前を付けてください。
型推論でJVM言語を使用する場合は、Scalaを使用できます。
いくつかの理由が考えられます。1つは、明示的な型指定は自己文書化であるということです。Javaは通常、これを簡潔さよりも優先します。もう1つの理由は、型が多少あいまいな場合です。タイプまたはサブタイプがルーチンを満たす場合のように。リストを使用したいが、誰かがやって来て、ArrayList専用のメソッドを使用するとします。JITはArrayListを推測し、コンパイルエラーが必要な場合でも続行します。
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
-私はこのビットを理解していません。型の推論は、変数のメソッドを呼び出すのではなく、変数のインスタンス化の瞬間に行われます。おそらくあなたが何を意味するのか例を示していただけますか?
これは、ニーズに合う最も一般的なインターフェイスを使用して変数を宣言し、次のように適切な実装クラスで初期化するという確立された推奨事項と矛盾します
Collection<String> names = new ArrayList<>();
事実上、
var names = new ArrayList<String>();
のための構文糖に過ぎない
ArrayList<String> names = new ArrayList<String>();
必要に応じて、IDEはnew ArrayList<String>()
「ワンクリック」式(リファクタリング/ローカル変数の作成)で式から生成できますが、「インターフェイスの使用」の推奨事項と矛盾することに注意してください。