Java 7'de elmas operatörünün (<>) anlamı nedir?


446

Java 7'deki elmas operatörü aşağıdaki gibi kodlara izin verir:

List<String> list = new LinkedList<>();

Ancak Java 5/6'da yazabilirim:

List<String> list = new LinkedList();

Tip silme anlayışım, bunların tamamen aynı olduğudur. (Jenerik yine de çalışma zamanında kaldırılır).

Neden elmasla uğraşasınız ki? Hangi yeni işlevsellik / tip güvenliğine izin veriyor? Yeni bir işlevsellik sağlamazsa neden bir özellik olarak bahsediyorlar? Bu kavram hakkındaki anlayışım kusurlu mu?


4
Java, yöntem çağrılarında çıkarım yazdığından, statik fabrika yöntemleri kullanıyorsanız bunun bir sorun olmadığını unutmayın.
Brian Gordon

uyarıyı devre dışı bıraktığınızda aslında işe yaramaz ... :) benim gibi
Renetik


DZone hakkında güzel bir yazı .
R. Oosterholt

2
Benim görüşüm List <String> list = new LinkedList <Soldaki tür ne olursa olsun> () için sözdizimsel şeker olmasıdır. yani jenerik tutmak
Viktor Mellgren

Yanıtlar:


497

İle ilgili sorun

List<String> list = new LinkedList();

sol tarafta , sağdaki ham türü kullandığınız genel türü List<String>kullanmanızdır . Java'daki ham türler yalnızca pre-generics koduyla uyumluluk için etkili bir şekilde bulunur ve kesinlikle gerekmedikçe asla yeni kodlarda kullanılmamalıdır.LinkedList

Şimdi, Java başından beri jeneriklere sahipse ve LinkedListorijinal olarak jeneriklere sahip olmadan önce oluşturulmuş gibi türlere sahip değilse , muhtemelen genel bir tür için yapıcı otomatik olarak soldan tür parametrelerini ihlal edebilirdi - mümkünse ödevin tarafı. Ancak olmadı ve geriye dönük uyumluluk için ham türleri ve genel türleri farklı şekilde ele almalıdır. Bu onların tür parametrelerini tekrarlamak zorunda kalmadan genel bir nesnenin yeni bir örneğini ... elmas operatörünü bildirmek için biraz farklı , ama aynı derecede kullanışlı bir yol yapma ihtiyacı bırakıyor .

Orijinal örneğinize göre List<String> list = new LinkedList(), derleyici bu ödev için bir uyarı oluşturur çünkü zorunludur. Bunu düşün:

List<String> strings = ... // some list that contains some strings

// Totally legal since you used the raw type and lost all type checking!
List<Integer> integers = new LinkedList(strings);

Jenerikler, yanlış şeyi yapmaya karşı derleme zamanı koruması sağlamak için mevcuttur. Yukarıdaki örnekte, raw türünü kullanmak, bu korumayı alamayacağınız ve çalışma zamanında bir hata alacağınız anlamına gelir. Bu yüzden ham türleri kullanmamalısınız.

// Not legal since the right side is actually generic!
List<Integer> integers = new LinkedList<>(strings);

Bununla birlikte, elmas operatörü, atamanın sağ tarafının, bu parametreleri tekrar yazmak zorunda kalmadan, sol tarafla aynı tip parametrelerine sahip gerçek bir genel örnek olarak tanımlanmasını sağlar. Ham tipi kullanmakla neredeyse aynı çabayla jeneriklerin güvenliğini korumanıza izin verir .

Bence anlaşılması gereken en önemli şey, ham türlerin (no ile <>) genel türlerle aynı şekilde ele alınamayacağıdır. Ham bir tür bildirdiğinizde, jeneriklerin hiçbir faydası ve tür kontrolünü elde edemezsiniz. Ayrıca, jeneriklerin Java dilinin genel amaçlı bir parçası olduğunu da aklınızda bulundurmanız gerekir ... onlar sadece Collections no-arg kurucuları için geçerli değildir !


31
Geriye dönük uyumluluk harika, ancak karmaşıklık pahasına değil. Java 7 neden -compatibilityderleyici anahtarını sunamazken, yoksa javactüm ham türleri yasaklayacak ve sadece genel türleri zorlayacaktır? Bu, kodlarımızı olduğu gibi daha az ayrıntılı hale getirecektir.
Rosdi Kasım

3
@Rosdi: Kabul etti, yeni kodda ham türlere gerek yok. Ancak, Java sürüm numarasını kaynak dosyaya (komut satırını kullanarak (mis) yerine) eklemeyi kesinlikle tercih ederim, cevabımı görün.
maaartinus

37
Ben şahsen aynı hat üzerinde tanımladığınız VE somutlaştırdığınız elmasların kullanımını sevmiyorum. List<String> strings = new List<>()sorun değil, ancak private List<String> my list;örneğini oluşturduğunuz sayfanın yarısını belirlerseniz , my_list = new List<>()sorun olmazsa! Listem tekrar ne içeriyor? Ah, tanım için etrafta dolaşayım. Aniden, elmas kısayolunun yararı hoşçakalıyor.
rmirabelle

11
@rmirabelle Nasıl o farklıdır: my_list = getTheList()? Bu tür sorunlarla başa çıkmanın birkaç daha iyi yolu vardır: 1. fare imlecinde değişken türlerini gösteren bir IDE kullanın. 2. gibi daha anlamlı değişken adları kullanın private List<String> strings3. gerçekten gerekmedikçe değişkenlerin bildirimi ve ilklendirmesini bölmeyin.
Natix

1
@Morfidon: Evet, hala Java 8 için geçerli. Eminim uyarılar almalısınız .
ColinD

37

Anlayışınız biraz kusurlu. Elmas operatörü, kendinizi tekrarlamanız gerekmediği için güzel bir özelliktir. Türü bildirdiğinizde türü bir kez tanımlamak mantıklıdır, ancak sağ tarafta tekrar tanımlamak mantıklı değildir. KURU ilkesi.

Şimdi türleri tanımlamakla ilgili tüm belirsizlikleri açıklayacağız. Tür çalışma zamanında kaldırılır, ancak tür tanımına sahip bir Listeden bir şey almak istediğinizde, listeyi bildirirken tanımladığınız tür olarak geri alırsınız, aksi takdirde tüm belirli özellikleri kaybeder ve yalnızca Alınan nesneyi, bazen çok zor olabilen ve bir ClassCastException özelliğiyle sonuçlanabilecek orijinal türüne ne zaman atayacağınız dışındaki nesne özellikleri.

Kullanmanız List<String> list = new LinkedList()size ham tür uyarıları verecektir.


8
List<String> list = new LinkedList()doğru koddur. Bunu biliyorsun ve ben de biliyorum. Ve soru (anladığım kadarıyla): neden sadece java derleyici bu kodun oldukça güvenli olduğunu anlamıyor?
Roma

22
@Roman: List<String> list = new LinkedList()olduğu değil doğru kodu. Tabii, olsaydı iyi olurdu! Ve muhtemelen Java'nın en başından beri jenerikleri olsaydı ve eskiden jenerik olmayan jenerik tiplerin geriye dönük uyumluluğu ile uğraşmak zorunda kalmamış olabilirdi, ama öyle.
ColinD

6
@ColinD Java'nın gerçekten her bir satırda geriye dönük uyumluluk ile uğraşmasına gerek yoktur . Jenerikler kullanan herhangi bir Java kaynak dosyasında eski jenerik olmayan türler yasaklanmalıdır ( <?>eski kodla arayüz oluştururken her zaman kullanabilirsiniz ) ve yararsız elmas operatörü mevcut olmamalıdır.
maaartinus

16

Bu satır [işaretlenmemiş] uyarısına neden olur:

List<String> list = new LinkedList();

Öyleyse, soru dönüşüyor: neden [işaretlenmemiş] uyarısı yalnızca yeni koleksiyon oluşturulduğunda otomatik olarak bastırılmıyor?

Bence, <>özellik eklemekten çok daha zor bir iş olurdu .

UPD : Ben de yasal olarak 'sadece birkaç şey için' ham türleri kullanmak olsaydı bir karışıklık olacağını düşünüyorum.


13

Teorik olarak, elmas operatörü tekrarlanan tür argümanlarını kaydederek daha kompakt (ve okunabilir) kod yazmanıza izin verir. Pratikte, sadece kafa karıştırıcı iki karakter daha fazla bir şey vermiyor. Neden?

  1. Hiçbir aklı başında programcı yeni kodda ham türleri kullanmaz. Böylece derleyici, herhangi bir tür argüman yazmadan, onları çıkarmasını istediğinizi varsayabilir.
  2. Elmas operatör hiçbir tür bilgi sağlamaz, derleyiciye "iyi olur" der. Yani atlayarak zarar veremezsiniz. Elmas operatörünün yasal olduğu herhangi bir yerde, derleyici tarafından "çıkarılabilir".

Bir kaynağı Java 7 olarak işaretlemenin açık ve basit bir yoluna sahip olan IMHO, bu garip şeyleri icat etmekten daha yararlı olacaktır. Bu kadar belirgin kodda ham tipler hiçbir şey kaybetmeden yasaklanabilir.

Btw., Bir derleme anahtarı kullanılarak yapılması gerektiğini düşünmüyorum. Bir program dosyasının Java sürümü dosyanın bir özelliğidir, hiçbir seçenek yoktur. Önemsiz bir şeyi kullanmak

package 7 com.example;

bunu netleştirebilir (bir veya daha fazla süslü anahtar kelime dahil daha karmaşık bir şeyi tercih edebilirsiniz). Farklı Java sürümleri için yazılan kaynakların sorunsuz bir şekilde derlenmesine bile izin verir. Herhangi bir uyumluluğu kaybetmeden yeni anahtar kelimelerin (ör. "Modül") girilmesine veya bazı eski özelliklerin (tek bir dosyada veya hiçbir şekilde ortak olmayan iç içe olmayan sınıfların) bırakılmasına izin verir.


2
Arasındaki farkı düşündünüz mü new ArrayList(anotherList)ve new ArrayList<>(anotherList)(atandığı ediliyor özellikle List<String>ve anotherListbir olduğunu List<Integer>)?
Paul Bellora

@Paul Bellora: Hayır. Şaşırtıcı bir şekilde benim için her ikisi de derleniyor. Pırlantalı olan bile uyarı vermedi. Ancak, bununla ilgili herhangi bir anlam göremiyorum, biraz açıklayabilir misiniz?
maaartinus

Üzgünüm, çok iyi açıklayamadım. Bu iki örnek arasındaki farka bakın: ideone.com/uyHagh ve ideone.com/ANkg3T En azından jenerik sınırlara sahip argümanlar aktarılırken ham tür yerine elmas operatörünün kullanılmasının önemli olduğunu belirtiyorum. içinde.
Paul Bellora

Aslında ColinD'nin cevabını okumak için zaman ayırmamıştım - hemen hemen aynı şeyi belirtiyor.
Aralık'ta Paul Bellora

2
Yani, ham türler için, gerçekten ihtiyaç duyulan birkaç yer için yeni bir sözdizimi sunmak üzereysek, neden böyle bir şey kullanmıyorsunuz new @RawType List()? Zaten geçerli olan Java 8 sözdizimi ve tür ek açıklamaları, gerektiğinde her yerde kullanılmasına izin verir, örn @RawType List = (@RawType List) genericMethod();. Ham türlerin, uygun bir @SuppressWarningsyerleştirme yapılmadıkça şu anda bir derleyici uyarısı oluşturduğu dikkate alındığında, @RawTypemakul bir değiştirme olacaktır ve daha ince bir sözdizimi gerekli değildir.
Holger

8

Yazarken List<String> list = new LinkedList();, derleyici "denetlenmemiş" uyarısı verir. Bunu göz ardı edebilirsiniz, ancak bu uyarıları yoksaydıysanız, gerçek bir güvenlik sorunu hakkında sizi uyaran bir uyarıyı da kaçırabilirsiniz.

Bu nedenle, fazladan uyarı oluşturmayan bir kod yazmak daha iyidir ve elmas operatörü, gereksiz tekrarlama yapmadan bunu uygun bir şekilde yapmanızı sağlar.


4

Diğer yanıtlarda söylenenlerin tümü geçerlidir, ancak kullanım durumları tamamen geçerli değildir IMHO. Guava ve özellikle koleksiyonlarla ilgili şeyleri kontrol ederseniz , aynı statik yöntemlerle yapılmıştır. Örneğin Lists.newArrayList () yazma yapmanızı sağlar

List<String> names = Lists.newArrayList();

veya statik içe aktarma ile

import static com.google.common.collect.Lists.*;
...
List<String> names = newArrayList();
List<String> names = newArrayList("one", "two", "three");

Guava'nın bunun gibi çok güçlü özellikleri var ve aslında <> için çok fazla kullanım düşünemiyorum.

Elmas operatörü davranışını varsayılan yapmak için gitselerdi, yani tür, ifadenin sol tarafından çıkarılırsa veya sol tarafın türü sağ taraftan çıkarılırsa daha yararlı olurdu. İkincisi Scala'da olan şeydir.


3

Diamond operatörünün amacı, genel türler bildirilirken kod yazımını azaltmaktır. Çalışma zamanı üzerinde herhangi bir etkisi yoktur.

Java 5 ve 6'da belirtirseniz tek fark,

List<String> list = new ArrayList();

Belirtmek olması @SuppressWarnings("unchecked")için list(aksi takdirde alacak denetlenmeyen döküm uyarısı). Anladığım kadarıyla, elmas operatörü gelişimi kolaylaştırmaya çalışıyor. Jeneriklerin çalışma zamanında yürütülmesi üzerinde hiçbir ilgisi yok.


bu ek açıklamayı kullanmak zorunda bile değilsiniz. En azından Eclipse'de, derleyiciye sizi bu konuda
uyarmamasını söyleyebilirsiniz

Ek açıklamaya sahip olmak daha iyidir. Her geliştirici Eclipse'i burada kullanmıyor.
Buhake Sindi
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.