Java'daki C # 'var' anahtar kelimesinin eşdeğeri nedir?


264

C # içinde var anahtar sözcüğünün bir kullanımı örtük tür bildirimidir. İçin Java eşdeğer sözdizimi nedir var ?


4
val(veya var) belirli bir "Java değiştirme" dili kullanıyorsanız ;-)

6
@pst: Scala olur mu? Hm evet, öyle.
rsenna

IntelliJ için bunu bir özellik isteği olarak gönderdim: youtrack.jetbrains.com/issue/IDEA-102808 IDE, temel kod sahip olmasa bile val veya var değerini göstermek için kodu daraltabilir.
Jon Onstott

@Jon IntelJ için bir şeyleri hackledim, cevabımı görün .
balpha

3
Artık bu özelliğin Java'ya dahil edilmesi için bir teklif var - openjdk.java.net/jeps/286
McGin

Yanıtlar:


248

Hiç yok. Ne yazık ki, tam tip adını yazmanız gerekiyor.

Düzenleme: Gönderildikten 7 yıl sonra var, Java 10'da yerel değişkenler için (ile ) tür çıkarımı eklendi.

Düzenleme: Gönderildikten 6 yıl sonra, aşağıdan bazı yorumları toplamak için:

  • C # varanahtar sözcüğüne sahip olmasının nedeni , .NET'te adı olmayan Türlere sahip olmanızdır. Örneğin:

    var myData = new { a = 1, b = "2" };

    Bu durumda, uygun bir tip vermek imkansız olacaktır myData. 6 yıl önce, Java'da bu imkansızdı (son derece ayrıntılı ve tuhaf olsalar bile, tüm Türlerin isimleri vardı). Bunun bu arada değişip değişmediğini bilmiyorum.

  • varile aynı değildir dynamic. variable'lar hala% 100 statik olarak yazılmıştır. Bu derlenmeyecektir:

    var myString = "foo";
    myString = 3;
    
  • vartür bağlamdan açık olduğunda da kullanışlıdır. Örneğin:

    var currentUser = User.GetCurrent();

    Sorumlu olduğum herhangi bir kodda, currentUseriçinde bir Userveya türetilmiş sınıf olduğunu söyleyebilirim. Açıkçası, eğer User.GetCurrentbir int dönüşü uygulama , o zaman belki bu sizin için zararlıdır.

  • Bunun bir ilgisi yok var, ancak yöntemleri diğer yöntemlerle (örn. new public void DoAThing()) Gölgelediğiniz garip kalıtım hiyerarşileriniz varsa , sanal olmayan yöntemlerin, kullanıldıkları Türden etkilendiğini unutmayın.

    Bunun iyi bir tasarımın göstergesi olduğu gerçek bir dünya senaryosu hayal edemiyorum, ancak bu beklediğiniz gibi çalışmayabilir:

    class Foo {
        public void Non() {}
        public virtual void Virt() {}
    }
    
    class Bar : Foo {
        public new void Non() {}
        public override void Virt() {}
    }
    
    class Baz {
        public static Foo GetFoo() {
            return new Bar();
        }
    }
    
    var foo = Baz.GetFoo();
    foo.Non();  // <- Foo.Non, not Bar.Non
    foo.Virt(); // <- Bar.Virt
    
    var bar = (Bar)foo;
    bar.Non();  // <- Bar.Non, not Foo.Non
    bar.Virt(); // <- Still Bar.Virt
    

    Belirtildiği gibi, sanal yöntemler bundan etkilenmez.

  • Hayır, vargerçek değişken olmadan başlatmak için beceriksiz bir yol yoktur .

    var foo1 = "bar";        //good
    var foo2;                //bad, what type?
    var foo3 = null;         //bad, null doesn't have a type
    var foo4 = default(var); //what?
    var foo5 = (object)null; //legal, but go home, you're drunk
    

    Bu durumda, sadece eski moda bir şekilde yapın:

    object foo6;

11
@Mike Caron: C #, [varsayılan] sanal olmayan çağrılara sahiptir ve operatörler sanal var p = new X(); p.Z()değildir, bu yüzden ... SuperX p = new X(); p.Z()tüm X ve ve SuperX ile aynı değildir X : SuperX. İle statik Çeşidi daima ama daima, yukarıdaki ilk örnekte ikinci örnekteki. Dikkat edilmesi gereken ince ama önemli bir fark. Ama cevabınız çok doğru :-)varpXSuperX

200
@Jon Hanna: varkodu daha az netleştirmez. Bence tam tersi. Örneğin, türünü bildirip başlatırken ( RadioButton radioButton = new RadioButton();) neden aynı satıra iki (hatta üç) kez yazıyorsunuz ? vardeğişkenlerinizi adlandırırken iki kez düşünmeyi tercih eder, çünkü odağı türden ziyade işlevselliğe dönüştürür (örneğin, UserCollection collection = new userRepository.GetUsers();daha doğal olarak dönüşür var users = userRepository.GetUsers();). Eğer varbelirsiz olduğunu düşünüyorsanız , bunun nedeni kullanılmamış olmasıdır.
Martin Odhelius

4
@MartinOdhelius varkesinlikle kodun iyi kullanılmasını sağlayabilir, ama aynı zamanda çok kötü kullanılmasını da belirsiz hale getirebilir; birçok biçimlendirme seçeneği gibi. Denge, her ikisi de .NET 1.0'da bulunmayan anonim nesneleri ve jenerikleri ne kadar kullandığınıza bağlı olarak değişir ve C♯'nin ilk sürümünde varsayımsal bir anahtar kelime olarak daha az kullanışlı hale gelir. RadioButton radioButtonDüğmeye ilişkin önemli olan tek şeyin a olduğu bir fabrika veya yardımcı yöntem söz konusu olduğunda yalnızca bir ad verirdim RadioButton, aksi takdirde bu olan veya olmayan delilik var.
Jon Hanna

6
@Jon Hanna: Bir keresinde varsenin kadar eleştireldim , daha fazla olmasa da, fikrimi değiştirdim ve belki de farklı görüşler sorusu kadar basit, çünkü bunun bir şey olduğunu söylediğinde hala yanlış olduğunu düşünüyorum. anonim nesneleri ve jenerikleri ne kadar kullandığınız önemli değildir;) Tip bildirimi çoğunlukla sadece kod gürültüsüdür, kod olmadan anlayamıyorsanız, kod her iki durumda da muhtemelen belirsizdir.
Martin Odhelius

3
Sen karıştırıyorsun Var olan anonim tipler . varkendisi derleyiciden türü atamadan çıkarmasını ister; sözdizimsel şeker. İlk başta şüpheliydim, ama dini olarak kullanıyorum ve henüz karışıklığa neden olduğu bir zamanla karşılaşmadım. Örnekleme yapılırken fazlalığı ortadan kaldırır ve referans verirken türü kontrol etme ihtiyacını ortadan kaldırır. JAVA 9'dan itibaren JAVA eşdeğeri yoktur.
Robear

46

Projenize Lombok eklerseniz, val anahtar sözcüğünü kullanabilirsiniz .

http://projectlombok.org/features/val.html


1
@rightfold: Referansı finalmutlaka değiştirilemeyen nesneler . Düşününfinal StringBuilder strB = new StringBuilder("My reference is final"); strB.append("I'm not immutable");
Matthias Braun

1
Lombok v1.16.12'den beri de deneysel destek var var. projectlombok.org/features/experimental/var.html
Roel Spilker

@MatthiasBraun örneğiniz yanlış. Bu durumda StringBuilder sınıfının kendisi değiştirilemez, sadece yöntemi kullanarak iç yapısına dize değeri eklersiniz, bu tamamen yasaldır.
Andzej Maciusovic

27

JEP - JDK Geliştirme-Teklif

http://openjdk.java.net/jeps/286

JEP 286: Yerel Değişken Türü Çıkarım

Yazar Brian Goetz

// Goals:
var list = new ArrayList<String>();  // infers ArrayList<String>
var stream = list.stream();          // infers Stream<String>

Hangi Java sürümü? 10?
Peter Mortensen

@PeterMortensen Evet. JEP 286, JDK 10'da kabul edilmiş ve yayınlanmıştır (bkz. Openjdk.java.net/projects/jdk/10 adresindeki Özellikler altında 286 ).
Justin Albano

20

IntelliJ için bir şekilde - varJava ile size bir eklenti hazırladım . Bu bir hack, bu yüzden olağan feragatnameler geçerlidir, ancak Java geliştirmeniz için IntelliJ kullanıyorsanız ve denemek istiyorsanız, https://bitbucket.org/balpha/varsity adresindedir .


Mevcut düzenleyicide bildirim türlerini katlamak / açmak için bir klavye kısayoluna sahip olmak harika olurdu. Büyük eklenti olsa.
kısayol tuşu

2
@hotkey IntelliJ'in yerleşik kod katlamasını kullanır, böylece her şeyi Ctrl-Shift-NumPadPlus ile açabilirsiniz. İmleç, katlanmış değişken bildirimi içeren bir satır üzerindeyken, geçerli yöntemdeki bildirimleri katlamak / açmak için Ctrl-NumPadPlus ve Ctrl-NumPadMinus öğelerini kullanabilirsiniz. Tüm bildirimleri katlamak biraz garip, her şeyi katladınız (Ctrl-Shift-NumPadMinus) ve sonra her şeyi tekrar açın (Ctrl-Shift-NumPadPlus).
balpha

18

JDK 10'un 20 Mart'ta piyasaya sürülmesiyle, Java artık JEP 286'davar belirtildiği gibi ayrılmış bir tür adı (anahtar kelime değil - aşağıya bakın) içerir . Yerel değişkenler için Java 10 veya sonraki sürümlerde şu anda geçerlidir:

var map = new HashMap<String, Integer>();

varJava ayrılmış tür adı neredeyse aynıdır varhem örtük tiplemesi için (önemli farklar için aşağıya bakınız) izin vermesini de C # anahtar kelime. varJava'da yalnızca aşağıdaki bağlamlarda ( JEP 286: Hedeflerde numaralandırıldığı gibi) örtük tür çıkarımı için kullanılabilir :

  • başlatıcılı yerel değişkenler
  • gelişmiş for döngüsündeki dizinler
  • yerel bir for-döngüsü ilan

Bu nedenle var olamaz alanlar, dönüş türleri, sınıf adları veya arayüz adları için kullanılabilir. Gerekçesi, JEP 286'da (Brian Goetz tarafından yazılan) belirtildiği gibi, yerel değişkenleri bildirirken ve tanımlarken uzun tip adlarının dahil edilmesi ihtiyacını ortadan kaldırmaktır :

Java kodunun yazılmasıyla ilişkili töreni azaltarak, Java'nın statik tip güvenliğe olan bağlılığını koruyarak, geliştiricilerin yerel değişken türlerinin genellikle gereksiz bildirimlerini kullanmasına izin vererek geliştirici deneyimini geliştirmeye çalışıyoruz.

var Java'da kapsam belirleme

varJava'da bir anahtar kelime değil, ayrılmış bir tür adı olduğuna dikkat edilmelidir . JEP 286'dan alıntılandığı gibi:

Var tanımlayıcısı bir anahtar kelime değildir; bunun yerine ayrılmış bir tür adıdır. Bu, değişken, yöntem veya paket adı olarak var kullanan kodun etkilenmeyeceği anlamına gelir; sınıf veya arabirim adı olarak var kullanan kod etkilenir (ancak bu adlar alışılmış adlandırma kurallarını ihlal ettikleri için uygulamada nadirdir).

varAnahtar sözcük değil, ayrılmış bir tür adı olduğundan , paket adları, yöntem adları ve değişken adları için de kullanılabilir (yeni tür parazit rolüyle birlikte). Örneğin, aşağıdakiler varJava'nın geçerli kullanımlarına ilişkin örneklerdir :

var i = 0;
var var = 1;
for (var i = 0; i < 10; i++) { /* ... */ }
public int var() { return 0; }
package var;

JEP 286'dan alıntılandığı gibi:

Bu tedavi, başlatıcılarla yerel değişkenlerle, gelişmiş for-loop'taki indekslerle ve geleneksel for-loop'ta beyan edilen yerellerle sınırlı olacaktır; yöntem formları, yapıcı formları, yöntem döndürme türleri, alanlar, yakalama formları veya başka herhangi bir değişken bildirimi için kullanılamaz.

varJava & C Arasındaki Farklar

Bu varC # ve Java arasındaki önemli bir fark aşağıdakileri içerir: varC # 'da bir tür adı olarak kullanılabilir, ancak Java'da bir sınıf adı veya arabirim adı olarak kullanılamaz. Göre C # belgelerine (Dolaylı olarak Yazılan Yerel Değişkenler) :

Adlandırılmış bir tür varkapsamdaysa, varanahtar kelime bu tür adına çözümlenir ve örtük olarak yazılan bir yerel değişken bildiriminin parçası olarak değerlendirilmez.

varC # 'da bir tür adı olarak kullanılabilmesi , bazı karmaşıklıklar yaratır ve varJava'da varbir sınıf veya arabirim adı olarak izin vermeyerek kaçınılması gereken bazı karmaşık çözünürlük kurallarını getirir . varC # 'da tür adlarının karmaşıklığı hakkında bilgi için , bkz. Kısıtlanmış türdeki değişken bildirimleri için kısıtlamalar geçerlidir . `Var in Java için kapsam belirleme kararının ardındaki mantık hakkında daha fazla bilgi için, bkz. JEP 286: Kapsam Belirleme Seçenekleri .


Java ve c # arasında varalanlar veya dönüş türleri için kullanamayacağınız bir fark var mı ? Not etmek neden önemlidir?
user1306322

@ user1306322 Bu bağlamda, hayır. varJava'da alanlar veya dönüş türleri için kullanılamaz. Bu önemlidir, çünkü bu kısıtlama varbağlamı hassas hale getirir , burada sadece bazı bağlamlarda (yerel değişkenler) kullanılabilir, diğerleri değil. Bu mutlaka Java ve C # arasında dikkat edilmesi gereken bir fark değil var, Java'da kullanılırken genel olarak önemli bir kısıtlamadır .
Justin Albano

Ben sadece baktı ve c # gibi görünüyor varbir sınıf adı yapmak ve bu şekilde kullanabilirsiniz. Teknik olarak c # durumunda bir "bağlam anahtar kelimesi" dir, ancak Java'da aynı şeyi yapamazsınız. Yanlışsam düzelt.
user1306322

1
Haklısın. Sen kullanamazsınız varbir sınıf adı veya (yaygın zaten değildir) Java arabirim adı olarak, ancak değişken isimler, yöntem adları ve paket isimleri için kullanabilirsiniz. Örneğin, var var = 1;geçerli bir Java deyimi ancak bir sınıf bildirmek için çalışıyor olduğu public class var {}hatayla sonuçları: as of release 10, 'var' is a restricted local variable type and cannot be used for type declarations. varJava'daki mantık ve varC # ile arasındaki farklar hakkında daha ayrıntılı bilgi almak için yukarıdaki cevabı güncelledim .
Justin Albano

11

JDK 10'da desteklenecek. Erken erişim derlemesinde çalışırken görmek bile mümkün .

JEP 286 :

Başlatıcılarla yerel değişkenlerin bildirimlerine yazılan çıkarımları genişletmek için Java Dili'ni geliştirin.

Şimdi yazmak yerine:

List<> list = new ArrayList<String>();
Stream<> stream = myStream();

Sen yaz:

var list = new ArrayList<String>();
var stream = myStream();

Notlar:

  • varşimdi ayrılmış bir tür adı
  • Java hala statik yazım taahhüdüdür!
  • Yalnızca yerel değişken bildirimlerinde kullanılabilir

Yerel sisteminize Java'yı yüklemeden denemek istiyorsanız, üzerinde JDK 10 yüklü bir Docker görüntüsü oluşturdum :

$ docker run -it marounbassam/ubuntu-java10 bash
root@299d86f1c39a:/# jdk-10/bin/jshell
Mar 30, 2018 9:07:07 PM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
|  Welcome to JShell -- Version 10
|  For an introduction type: /help intro

jshell> var list = new ArrayList<String>();
list ==> []

3
Dikkat edin, sağladığınız kod (önce / sonra var) eşdeğer değildir. Olarak varörneğin listtiptedir ArrayList, bir değil List.
Gili

8

Basit bir çözüm (iyi bir IDE kullandığınızı varsayarsak), sadece her yere 'int' yazmanız ve ardından türü sizin için ayarlamanızdır.

Aslında 'var' adında bir sınıf ekledim, bu yüzden farklı bir şey yazmak zorunda değilim.

Kod hala çok ayrıntılı, ama en azından yazmak zorunda değilsiniz!


"İyi IDE" derken Eclipse * hariç tutulur mu? - Bu Luna'da işe yaramaz gibi görünüyor (en azından denediğimde int) - Bir şey mi kaçırıyorum? (*: Eclipse'e asla iyi bir IDE
demezken

@ BrainSlugs83 dunno IDEA kullanıyorum, gerçekten daha önce tutulma kullanılmadı. Sizin için türleri düzeltmiyor mu? Aslında düzgün çalışıyor dışında IDEA gibi c # / visual studio / resharper alışkınım! Tüm jetbrain'lerde, bir hata olduğunda önerilerin bir listesini almak için alt-enter tuşuna basabilirsiniz - bu nedenle int için türün ayarlanması bir hata verir, alt-giriş yapabilir ve türünü sıralayabilirsiniz
JonnyRaa

5

Kotlin'e JetBrains'ten bakabilirsiniz , ama val. var değil.


4
Kotlin'in val ve var. val, java'da değişken bir final bildirmeye eşdeğerdir, var yeniden atamaya izin verir.
samlewis

5

Java 10 yerel değişken tipi çıkarım elde etti, bu yüzden şimdi varC # bir (ben bildiğim kadarıyla) hemen hemen eşdeğer vardır.

Ayrıca, kınamayan türleri de çıkarabilir (programcı tarafından o yerde adlandırılamayan türler ; ancak hangi türlerin kınanamaz olduğu farklıdır). Örneğin bkz . İş yerinde asla kullanmamanız gereken hileler varve anonim sınıflar .

Bulabildiğim tek fark C # 'da,

Var adlı bir tür kapsamdaysa, var anahtar sözcüğü bu tür adına çözümlenir ve örtük olarak yazılan yerel değişken bildiriminin bir parçası olarak değerlendirilmez.

Java 10'da varyasal bir tür adı yoktur.


@Lii Evet, burada ne demek istediğimi hatırlamıyorum, kaldırıldı.
Alexey Romanov

Harika! Geçmişi temizlemek için yorumumu kaldıracağım!
Lii

4

Java 10 itibariyle eşdeğerdir ... var.


Var mıdır herhangi bir fark? Demek istediğim, bu gibi kısa cevaplar yazmaktan daha iyi biliyorsun, neyi temsil edersin? Ve elbette bazı farklılıklar olmalı .
user1306322

@ user1306322 Bu tamamen ayrı bir soru! Bunun birçok yönü sorulduğu için java-10 etiketini kontrol edebilirsiniz.
Brian Goetz

Peki, bu, ilk önce geldiği ve kenar çubuğundaki ilgili tüm gönderilerde bağlantılı olduğu için bunu google mı, bakmanız gereken soru. Bu yüzden, ona cevap veren ayrı bir soru biliyorsanız, en azından ona bağlantı verebilir veya cevabınızın bir kısmını cevabınıza ekleyebilirsiniz.
user1306322

3

Bu eski olduğunu biliyorum ama neden bir var sınıf oluşturmak ve farklı türleri ile yapıcılar oluşturmak ve hangi yapıcıların çağrıldığına bağlı olarak farklı türü ile var olsun. Bir türü diğerine dönüştürmek için yöntemler de oluşturabilirsiniz.


3

Lombokvar destekler ancak hala deneysel olarak sınıflandırılır:

import lombok.experimental.var;

var number = 1; // Inferred type: int
number = 2; // Legal reassign since var is not final
number = "Hi"; // Compilation error since a string cannot be assigned to an int variable
System.out.println(number);

İşte onu kullanmaya çalışırken kaçınmak için bir tuzak IntelliJ IDEA. Otomatik tamamlama ve her şey dahil olmak üzere beklendiği gibi çalışıyor gibi görünüyor. "Kesintisiz" bir çözüm olana kadar (örneğin, JEP 286: Yerel Değişken Türü Çıkarım nedeniyle ), bu şu anda en iyi bahsiniz olabilir.

Bir değişiklik yapmadan veya oluşturmadan da valdestek olduğunu unutmayın .Lomboklombok.config


2

Java 10'da, ancak yalnızca Yerel değişkenler için ,

Yapabilirsin,

var anum = 10; var aString = "Var";

Ama yapamam,

var anull = null; // Since the type can't be inferred in this case

Daha fazla bilgi için teknik özelliklere göz atın .


2
Bu yanlış. varyakalama türleri, kavşak türleri ve anonim sınıf türleri dahil olmak üzere birçok türden ifade edilemeyen tür için kullanılabilir. Java 11'den itibaren lambda parametrelerine de uygulanabilir.
Brian Goetz

0

Genel olarak herhangi bir tür için Object sınıfını kullanabilirsiniz, ancak daha sonra tür dökümünü yapmalısınız!

Örneğin:-

Object object = 12;
    Object object1 = "Aditya";
    Object object2 = 12.12;

    System.out.println(Integer.parseInt(object.toString()) + 2);

    System.out.println(object1.toString() + " Kumar");
    System.out.println(Double.parseDouble(object2.toString()) + 2.12);

Aditya, lütfen diğer tüm cevaplarını kontrol et. Birçoğu -1 ve muhtemelen iyi bir nedenden dolayı var. Bunun doğru olduğundan emin değilseniz, yalnızca yayınlama.
user1306322

@ user1306322 Cevabımdaki sorun nedir! detaylandırabilir misin Tüm veri türleri için Object sınıfını kullanamaz mıyız?
Aditya Kumar

Nesne nesnesi = 12; Object object1 = "Aditya"; Nesne nesnesi2 = 12.12; System.out.println (Integer.parseInt (object.toString ()) + 2); System.out.println (object1.toString () + "Kumar"); System.out.println (Double.parseDouble (object2.toString ()) + 2,12);
Aditya Kumar

Sorun şu ki, soruyu anlamadınız. Soru "bu iş nasıl yapılır" değil, "böyle bir şey var" idi. Yanlış soruya cevap veriyorsunuz. varŞimdi resmi olarak dilde olan kelimeyle, cevabınız da şimdi eski moda yoldan bahsediyor.
user1306322

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.