Java neden tür çıkarım yapmıyor?


44

Java'nın, dilin ne olduğu ve VM'nin çok olgun olması koşuluyla neden tür çıkarım yapmadığını her zaman merak etmişimdir. Google'ın Git mükemmel tür çıkarımı olan bir dilin bir örneğidir ve bir kişinin yazması gereken miktarı azaltır. Bu özelliğin arkasında Java'nın bir parçası olmamak için özel bir sebep var mı?


3
Java kadar eski ve popüler bir dilde geriye dönük uyumluluk kuralları
cırcır böceği

9
@ratchetfreak Yazım çıkarımı geriye dönük olarak eklenemez mi? Daha eski programlar sadece gerekenden daha fazla tip bilgi sağlardı.

1
Type Erasure ile birlikte kullanıldığında bazı istenmeyen etkileri olabilir. docs.oracle.com/javase/tutorial/java/generics/…
Zachary Yates

4
Java 8'in Lambda özelliği ile çok fazla tür çıkarım getireceğini unutmayın : Herhangi bir türden ve çıkarılan her şeyden söz etmeden karmaşık lambdalar yazabilirsiniz.
Joachim Sauer

4
Yerel değişken tipi çıkarımı Java'ya geliyor: JEP 286: Yerel Değişken Tipi Çıkarım
Jimmy Page

Yanıtlar:


60

Teknik olarak konuşursak, Java, jenerik kullanırken tür çıkarımı vardır . Bir ile genel yönteme gibi

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

Derleyici yazdığınızda bunu analiz eder ve anlar.

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

Bağımsız değişken olarak neyin girildiğine bağlı olarak ilk arama için bir Dize, ikinci arama için bir Tamsayı döndürülür. Sonuç olarak uygun derleme zamanı kontrolünü alacaksınız. Ek olarak, Java 7'de, bunun gibi jenerik ilaçları başlatırken bazı ek tür çıkarımlar elde edilebilir

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

Java bizim için boş köşeli parantezleri doldurmaya yetecek kadar naziktir. Şimdi Java neden değişken atamanın bir parçası olarak tip çıkarımını desteklemiyor ? Bir noktada, değişken bildirimlerinde tür çıkarımı için bir RFE vardı , ancak bu "düzeltmeyecek" olarak kapatıldı çünkü

İnsanlar, tip beyanının fazlalığından iki şekilde faydalanırlar. İlk olarak, gereksiz tür değerli belgeler olarak işlev görür; okuyucular, hangi türün döndürdüğünü bulmak için getMap () bildirgesini aramak zorunda değildir. İkincisi, artıklık programcının amaçlanan türü beyan etmesini ve böylece derleyici tarafından gerçekleştirilen çapraz kontrolden faydalanmasını sağlar.

Bunu kapatan katkıda bulunan, aynı zamanda hemfikir olduğum "java benzeri olmayan" bir his olduğunu da belirtti. Java'nın detaysızlığı hem bir nimettir hem de bir lanet olabilir, ancak dili olduğu gibi yapar.

Tabii ki bu belirli RFE bu konuşmanın sonu değildi. Java 7 sırasında, bu özellik, James Gosling'in kendisi de dahil olmak üzere bazı test uygulamaları oluşturularak tekrar ele alındı. Yine, bu özellik sonunda düşürüldü.

Java 8'in piyasaya sürülmesiyle birlikte, artık lambdaların bir parçası olarak tür çıkarımları alıyoruz:

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

Java derleyicisi, yönteme bakabiliyor Collections#sort(List<T>, Comparator<? super T>)ve sonra bunun arayüzünü araştırabiliyor Comparator#compare(T o1, T o2)ve belirliyor firstve bu nedenle programcının lambda ifadesindeki türü yeniden basmak zorunda kalmasına izin verecek şekilde secondolması gerektiğini belirtmelidir 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- evet, öyleyse HashMap<String, Integer> map = foo.getMap()katılıyorum - C # da Genelde bu vargibi durumlarda kullanabildiğim halde kullanmıyorum . Fakat eğer bu argüman su tutmaz HashMap<String, Integer> map = new HashMap<String, Integer>(). Bu gerçek artıklık ve tür adını iki kez yazmak zorunda kalmanın bir yararı yok. Ve burada bir derleyici çapraz kontrolünden nasıl faydalanacağımı, hiç anlamıyorum.
Konrad Morawski

9
Evet ve bu jenerikler için iyidir, fakat hala varJava # 'daki eşdeğerini özlüyorum .
Konrad Morawski

15
"Java olmayan" gibi, bu ( peynirli
Konrad Morawski

6
Ayrıca, bir fonksiyonun geri dönüş tipi genellikle açıktır veya gereksizdir ve IDE'niz olmadığı durumlarda bile, türü yarım saniye içinde işaretleyebilir.
Phoshi

8
Resmi teklifin Humans benefit from the redundancyşu anki sorunun asıl cevabı olduğuna inanıyorum , çünkü okuduğum her gerekçe Java tasarımcılarının basit, saçma ve saçma bir bahanesi gibi görünüyor: Hem C # hem de C ++ özelliğine sahip, C # ve C ++ tasarımcıları daha az yetkin değil Java'lar ve herkes onu kullanmaktan mutlu. Java geliştiricilerinin C # veya C ++ geliştiricilerinden farklı olmasına neden olan nedir? Bu yüzden @KonradMorawski ile aynı fikirdeyim, "Burada işlerin nasıl yürüdüğü" yine de bunun arkasındaki gerçek sebep gibi görünüyor .
paercebal

16

İlk olarak, tür çıkarımının çalışma zamanının vadesiyle hiçbir ilgisi yoktur, bu çalışma zamanının 30 yıllık bir CPU veya bitler hala çok parlak olan bir VM olduğu fark etmez. hepsi derleyici ile ilgili.

Bununla birlikte, jenerikler için izin veriliyor, jenerik olmayan tipler için izin verilmesinin nedeni felsefe nedeniyle görünüyor - tasarımcıların eklemesini engelleyen hiçbir şey yok.

Güncelleme: java 10'un desteklediği görülüyor —- http://openjdk.java.net/jeps/286


5

Bildiğim kadarıyla, Java doksanların başında tasarlandığında, tür çıkarımı ana diller arasında popüler değildi (ama zaten çok iyi bilinen bir kavramdı, örneğin ML'de). Bu nedenle, tür çıkarımının muhtemelen desteklenmediğini hayal edebiliyorum, çünkü Java, C ++, Pascal veya buna sahip olmayan diğer ana dillerden gelen programcılara yönelikti (en az sürpriz prensibi).

Ayrıca, Java’nın tasarım ilkelerinden biri, programcının ve derleyicinin aynı kod anlayışına sahip olduğundan emin olmak için açık bir şekilde şeyler yazmaktır: bilginin çoğaltılması hata olasılığını azaltır. Elbette, birkaç karakter daha yazmanın sağladığı ekstra güvenliğe değip değmeyeceği bir zevk meselesi olabilir, fakat bu Java için izlenen tasarım felsefesiydi: açıkça yazılan şeyler.

Gelecekte Java'nın türden çıkarım yapıp çıkmayacağını bilmiyorum ama IMO bu dil için büyük bir devrim niteliğinde olacak (Glenn Nelson'ın da belirttiği gibi "java benzeri olmayan" olarak tanımlandı) Java'yı yeni bir isim lehine adlandırın.

Yazım çıkarımına sahip bir JVM dili kullanmak istiyorsanız, Scala'yı kullanabilirsiniz.


2

Birkaç olası neden düşünebilirim. Birincisi, açık yazma işleminin kendi kendini belgelemesidir. Java genellikle bunu karar yerine göre öncelik haline getirir. Başka bir neden, türün biraz belirsiz olduğu durumlarda olabilir. Bir tür veya herhangi bir alt tipin bir rutini sağlaması gibi. Listeyi kullanmak istediğinizi varsayalım, ancak birileri gelir ve ArrayList'e özel bir yöntem kullanır. JIT bir ArrayList çıkarır ve bir derleme hatası istemeseniz bile devam eder.


8
GridBagLayout gridbag = nasıl new new GridBagLayout (); kendi kendine belgelere ekle? Saf tekrarı.
Anders Lindén

3
İki tipin aynı olmadığı bir durumdan ayrılıyor. Bir alt sınıfın örneğini kolayca atayabilirsiniz.
Jiggy

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- Bu şeyi anlamıyorum. Tür çıkarımı, bir değişkeni yerleştirme anında gerçekleşir, üzerinde bir yöntem yoktur. Belki de demek istediğinin bir örneğini gösterebilir misin?
Konrad Morawski

2
@KonradMorawski: Bir yöntem ArrayList'i döndürürse türün buna göre çıkacağı anlamına gelir. Bir türü dönüş türünden başka bir şey olarak değerlendirmek istiyorsanız, çıkarımı kullanamazsınız. Bununla birlikte, bunun aklı başında herhangi bir yerdeki bir kod tabanında nasıl bir problem olabileceğini anlamıyorum.
Phoshi

JIT, tür çıkarımında hiçbir rol oynamaz. tür çıkarımı bir derleme zamanı olgusudur. ve eğer bir değişken bir Listeye referans olarak bildirilirse, ArrayList üyelerine erişmeye çalışmak check
sara

0

Gereksinimlerinize en uygun arayüzü kullanarak değişkenleri bildirmek ve bunları aşağıdaki gibi uygun bir uygulama sınıfı ile başlatmak için iyi bilinen bir önerme ile çelişir.

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

Etkili bir şekilde,

var names = new ArrayList<String>();

sözdizimsel şekerden başka bir şey değil

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

İsterseniz, IDE'niz new ArrayList<String>()ifadeyi "tek tıklamayla" (refactor / create yerel değişken oluştur) ifadesinden üretebilir , ancak "arabirimleri kullan" önerisine aykırı olduğunu unutmayın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.