Apa yang setara dengan kata kunci C # 'var' di Jawa?

264

Salah satu penggunaan kata kunci var di C # adalah deklarasi tipe implisit. Apakah sintaks yang setara dengan Java untuk var ?

Arturo
sumber
4
val(atau var) jika Anda menggunakan bahasa "penggantian Java" tertentu ;-)
6
@ pst: apakah itu Scala? Hm ya, benar.
rsenna
Untuk IntelliJ, saya mengirimkan ini sebagai permintaan fitur: youtrack.jetbrains.com/issue/IDEA-102808 IDE dapat menciutkan kode untuk menampilkan val atau var meskipun kode yang mendasarinya tidak memilikinya.
Jon Onstott
@Jon Saya sudah meretas sesuatu bersama untuk IntelliJ, lihat jawaban saya .
balpha
3
Sekarang ada proposal untuk fitur ini untuk dimasukkan dalam Java - openjdk.java.net/jeps/286
McGin

Jawaban:

248

Tidak ada. Sayangnya, Anda harus mengetikkan nama tipe lengkap.

Sunting: 7 tahun setelah diposting, ketik inferensi untuk variabel lokal (dengan var) ditambahkan di Java 10.

Sunting: 6 tahun setelah diposting, untuk mengumpulkan beberapa komentar dari bawah:

  • Alasan C # memiliki varkata kunci adalah karena itu mungkin untuk memiliki Jenis yang tidak memiliki nama di .NET. Misalnya:

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

    Dalam hal ini, tidak mungkin untuk memberikan tipe yang tepat myData. 6 tahun yang lalu, ini tidak mungkin di Jawa (semua Jenis memiliki nama, bahkan jika mereka sangat verbose dan tidak berbahaya). Saya tidak tahu apakah ini telah berubah dalam waktu yang bersamaan.

  • vartidak sama dengan dynamic. variables masih 100% diketik secara statis. Ini tidak akan mengkompilasi:

    var myString = "foo";
    myString = 3;
  • varjuga berguna ketika jenisnya jelas dari konteks. Sebagai contoh:

    var currentUser = User.GetCurrent();

    Saya dapat mengatakan bahwa dalam kode apa pun yang menjadi tanggung jawab saya, currentUsermemiliki Userkelas turunannya. Jelas, jika implementasi Anda User.GetCurrentmengembalikan int, maka mungkin ini merugikan Anda.

  • Ini tidak ada hubungannya dengan var, tetapi jika Anda memiliki hierarki pewarisan aneh di mana Anda membayangi metode dengan metode lain (mis. new public void DoAThing()), Jangan lupa bahwa metode non-virtual dipengaruhi oleh Tipe yang mereka gunakan.

    Saya tidak bisa membayangkan skenario dunia nyata di mana ini menunjukkan desain yang baik, tetapi ini mungkin tidak berfungsi seperti yang Anda harapkan:

    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

    Seperti yang ditunjukkan, metode virtual tidak terpengaruh oleh ini.

  • Tidak, tidak ada cara non-canggung untuk menginisialisasi vartanpa variabel aktual.

    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

    Dalam hal ini, lakukan saja dengan cara lama:

    object foo6;
Mike Caron
sumber
11
@ Mike Caron: C # memiliki [default] panggilan non-virtual dan operator tidak virtual jadi ... var p = new X(); p.Z()tidak sama dengan SuperX p = new X(); p.Z()untuk semua X dan dan SuperX, meskipun X : SuperX. Dengan varyang statis jenis pselalu Xdalam contoh pertama di atas, tetapi selalu SuperXdalam contoh kedua. Perbedaan yang halus tetapi penting untuk diperhatikan. Tetapi jawaban Anda sangat benar :-)
200
@ Jon Hanna: vartidak membuat kode kurang jelas. Justru sebaliknya menurut saya. Mengapa misalnya menulis tipe dua (atau bahkan tiga) kali pada baris yang sama ketika Anda mendeklarasikan dan membuat instance ( RadioButton radioButton = new RadioButton();)? varmembuat Anda lebih suka berpikir dua kali ketika Anda memberi nama variabel Anda karena itu mengubah fokus pada fungsi daripada jenis (misalnya UserCollection collection = new userRepository.GetUsers();agak lebih alami berubah menjadi var users = userRepository.GetUsers();). Jika Anda pikir vartidak jelas itu hanya karena tidak terbiasa.
Martin Odhelius
4
@ MartinOdhelius varsangat jelas dapat membuat kode yang jelas digunakan dengan baik, tetapi juga dapat membuatnya tidak jelas terlalu buruk digunakan; seperti banyak opsi pemformatan. Saldo berbeda tergantung pada seberapa banyak Anda menggunakan objek dan generik anonim, yang tidak ada dalam. NET 1.0, menjadikannya kurang berguna sebagai kata kunci hipotetis dalam versi pertama C♯. Saya hanya akan menyebutkan RadioButton radioButtondalam kasus metode pabrik atau penolong di mana satu-satunya hal penting tentang tombol adalah bahwa itu adalah RadioButton, kalau tidak itu gila dengan atau tanpa var.
Jon Hanna
6
@ Jon Hanna: Saya pernah sama kritisnya dengan varAnda, jika tidak lebih, tapi saya telah mengubah pendapat saya, dan mungkin itu sesederhana pertanyaan pendapat yang berbeda, karena saya masih berpikir Anda salah ketika Anda mengatakan itu adalah peduli seberapa banyak Anda menggunakan objek anonim dan generik;) Deklarasi tipe paling sering hanya kode noise, jika Anda tidak dapat memahami kode tanpa itu kode mungkin tidak jelas dalam kedua kasus.
Martin Odhelius
3
Anda membingungkan var dengan tipe anonim . varitu sendiri hanya meminta kompiler untuk menyimpulkan jenis dari tugas; itu gula sintaksis. Awalnya saya ragu dengan itu, tetapi saya menggunakannya secara religius dan belum menemukan waktu di mana itu menyebabkan kebingungan. Ini menghilangkan redundansi saat instantiasi dan menghilangkan kebutuhan untuk memeriksa jenis ketika referensi. Tidak ada padanan JAVA pada JAVA 9.
Robear
46

Jika Anda menambahkan Lombok ke proyek Anda, Anda dapat menggunakan kata kunci val .

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

darthtrevino
sumber
1
@ rightfold: Objek yang referensi finaltidak selalu berubah. Pertimbangkanfinal StringBuilder strB = new StringBuilder("My reference is final"); strB.append("I'm not immutable");
Matthias Braun
1
Sejak lombok v1.16.12 ada juga dukungan eksperimental untuk var. projectlombok.org/features/experimental/var.html
Roel Spilker
@MatthiasBraun teladan Anda salah. Dalam hal ini kelas StringBuilder itu sendiri tidak dapat diubah, Anda hanya menambahkan nilai string ke struktur internal menggunakan metode, ini benar-benar legal.
Andzej Maciusovic
27

JEP - Proposal Peningkatan JDK

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

JEP 286: Inferensi Tipe Variabel Lokal

Penulis Brian Goetz

// Goals:
var list = new ArrayList<String>();  // infers ArrayList<String>
var stream = list.stream();          // infers Stream<String>
blueberry0xff
sumber
Apa versi Java? 10?
Peter Mortensen
@PeterMortensen Ya. JEP 286 telah diterima dan diterbitkan dalam JDK 10 (lihat 286 di bawah Fitur di openjdk.java.net/projects/jdk/10 ).
Justin Albano
20

Saya telah membuat plugin untuk IntelliJ yang - dengan cara - memberi Anda vardi Jawa. Ini adalah hack, jadi penafian yang biasa berlaku, tetapi jika Anda menggunakan IntelliJ untuk pengembangan Java Anda dan ingin mencobanya, itu ada di https://bitbucket.org/balpha/varsity .

balpha
sumber
Akan lebih baik memiliki pintasan keyboard untuk melipat / membuka jenis deklarasi di editor saat ini. Plugin bagus.
hotkey
2
@hotkey Ini menggunakan kode lipat bawaan IntelliJ, jadi Anda bisa membuka semuanya dengan Ctrl-Shift-NumPadPlus. Ketika kursor berada pada garis yang berisi deklarasi variabel terlipat, Anda bisa Ctrl-NumPadPlus dan Ctrl-NumPadMinus untuk melipat / membuka deklarasi dalam metode saat ini. Melipat semua deklarasi agak canggung, Anda harus melipat semuanya (Ctrl-Shift-NumPadMinus) lalu buka kembali semuanya (Ctrl-Shift-NumPadPlus).
balpha
18

Dengan dirilisnya JDK 10 pada 20 Maret, Java sekarang memasukkan varnama tipe yang dicadangkan (bukan kata kunci — lihat di bawah) sebagaimana ditentukan dalam JEP 286 . Untuk variabel lokal, berikut ini sekarang berlaku di Java 10 atau lebih tinggi:

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

Nama varjenis yang dicadangkan di Jawa hampir identik dengan varkata kunci dalam C # di mana keduanya memungkinkan untuk mengetik secara implisit (lihat di bawah untuk perbedaan penting). vardi Jawa hanya dapat digunakan untuk inferensi tipe implisit dalam konteks berikut (sebagaimana disebutkan dalam JEP 286: Tujuan ):

  • variabel lokal dengan inisialisasi
  • indeks dalam for-loop yang disempurnakan
  • penduduk setempat dinyatakan dalam for-loop tradisional

Oleh karena itu var tidak dapat digunakan untuk bidang, tipe pengembalian, nama kelas, atau nama antarmuka. Alasannya adalah untuk menghapus kebutuhan untuk memasukkan nama tipe panjang ketika mendeklarasikan dan mendefinisikan variabel lokal, sebagaimana dinyatakan dalam JEP 286 (ditulis oleh Brian Goetz):

Kami berupaya meningkatkan pengalaman pengembang dengan mengurangi upacara yang terkait dengan penulisan kode Java, sambil mempertahankan komitmen Java terhadap keamanan tipe statis, dengan memungkinkan pengembang untuk menghilangkan deklarasi manifes tipe variabel lokal yang seringkali tidak perlu.

var Pelingkupan di Jawa

Perlu dicatat bahwa varini bukan kata kunci di Jawa, melainkan nama jenis yang dilindungi undang-undang. Seperti dikutip dari JEP 286:

Identifier var bukan kata kunci; alih-alih itu adalah nama jenis yang dipesan. Ini berarti bahwa kode yang menggunakan var sebagai variabel, metode, atau nama paket tidak akan terpengaruh; kode yang menggunakan var sebagai nama kelas atau antarmuka akan terpengaruh (tetapi nama-nama ini jarang dalam praktik, karena mereka melanggar konvensi penamaan biasa).

Perhatikan bahwa karena varnama jenis yang dicadangkan dan bukan kata kunci, itu masih dapat digunakan untuk nama paket, nama metode, dan nama variabel (bersama dengan peran campur-jenisnya yang baru). Sebagai contoh, berikut ini adalah semua contoh penggunaan yang valid vardi Jawa:

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

Seperti dikutip dari JEP 286:

Perawatan ini akan dibatasi untuk variabel lokal dengan inisialisasi, indeks dalam for-loop yang disempurnakan, dan penduduk lokal dinyatakan dalam for-loop tradisional; itu tidak akan tersedia untuk formals metode, formor konstruktor, metode tipe pengembalian, bidang, formals tangkap, atau jenis lain dari deklarasi variabel.

Perbedaan Antara vardi Jawa & C

Ini adalah satu perbedaan penting antara vardalam C # dan Java termasuk yang berikut: vardapat digunakan sebagai nama jenis di C # tetapi tidak dapat digunakan sebagai nama kelas atau nama antarmuka di Jawa. Menurut dokumentasi C # (Variabel Lokal yang Diketik Secara Implisit) :

Jika suatu jenis nama varberada dalam lingkup, maka varkata kunci tersebut akan menyelesaikan ke nama jenis itu dan tidak akan diperlakukan sebagai bagian dari deklarasi variabel lokal yang diketik secara implisit.

Kemampuan untuk digunakan varsebagai nama tipe di C # menciptakan beberapa kompleksitas dan memperkenalkan beberapa aturan resolusi yang rumit, yang dihindari oleh vardi Jawa dengan melarang varsebagai nama kelas atau antarmuka. Untuk informasi tentang kompleksitas varnama jenis di C #, lihat Pembatasan berlaku untuk deklarasi variabel yang diketik secara implisit . Untuk informasi lebih lanjut tentang alasan di balik keputusan pelingkupan untuk `var di Jawa, lihat JEP 286: Pilihan Pelingkupan .

Justin Albano
sumber
Apakah ada perbedaan antara Java dan c # yang Anda tidak bisa gunakan varuntuk bidang atau jenis kembali? Mengapa penting untuk diperhatikan?
user1306322
@ user1306322 Dalam konteks itu, no. vardi Java tidak dapat digunakan untuk bidang atau mengembalikan tipe. Ini penting karena pembatasan ini membuat varkonteks peka, di mana ia hanya dapat digunakan dalam beberapa konteks (variabel lokal) dan bukan yang lain. Ini belum tentu perbedaan antara Java dan C # yang harus dicatat, tetapi pembatasan penting secara umum saat menggunakan vardi Jawa.
Justin Albano
Saya baru saja melihat ke atas dan sepertinya di c # Anda dapat membuat varnama kelas dan menggunakannya seperti itu. Secara teknis ini adalah "kata kunci konteks" dalam kasus c #, tetapi di Jawa tampaknya Anda tidak dapat melakukan hal yang sama. Koreksi saya jika saya salah.
user1306322
1
Anda benar. Anda tidak dapat menggunakannya varsebagai nama kelas atau nama antarmuka di Java (yang tidak umum), tetapi Anda dapat menggunakannya untuk nama variabel, nama metode, dan nama paket. Sebagai contoh, var var = 1;adalah pernyataan Java valid tetapi berusaha untuk menyatakan kelas sebagai public class var {}hasil dalam kesalahan: as of release 10, 'var' is a restricted local variable type and cannot be used for type declarations. Saya telah memperbarui jawaban di atas untuk lebih detail tentang alasan vardi balik Jawa dan perbedaannya dengan varC #.
Justin Albano
11

Ini akan didukung di JDK 10. Bahkan mungkin untuk melihatnya beraksi di build akses awal .

The JEP 286 :

Tingkatkan Bahasa Jawa untuk memperluas inferensi jenis ke deklarasi variabel lokal dengan inisialisasi.

Jadi sekarang alih-alih menulis:

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

Anda menulis:

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

Catatan:

  • varsekarang menjadi nama jenis yang dipesan
  • Java masih berkomitmen untuk mengetik statis!
  • Ini hanya dapat digunakan dalam deklarasi variabel lokal

Jika Anda ingin mencobanya tanpa menginstal Java di sistem lokal Anda, saya membuat gambar Docker dengan JDK 10 diinstal di dalamnya:

$ 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 ==> []
Maroun
sumber
3
Hati-hati, kode yang Anda berikan (sebelum / sesudah var) tidak setara. Dalam varcontohnya listadalah tipe ArrayList, bukan a List.
Gili
8

Solusi sederhana (dengan asumsi Anda menggunakan IDE yang layak) adalah cukup mengetik 'int' di mana saja dan kemudian membuatnya untuk mengatur jenisnya untuk Anda.

Saya sebenarnya baru saja menambahkan kelas yang disebut 'var' jadi saya tidak perlu mengetik sesuatu yang berbeda.

Kode masih terlalu bertele-tele, tetapi setidaknya Anda tidak harus mengetiknya!

JonnyRaa
sumber
Ketika Anda mengatakan "IDE yang layak" apakah Eclipse * dikecualikan? - ini tampaknya tidak berfungsi di Luna (setidaknya ketika saya baru saja mencobanya int) - apakah saya melewatkan sesuatu? (*: sementara saya tidak akan pernah menyebut Eclipse IDE yang layak, saya tidak bisa menilai untuk orang lain ...)
BrainSlugs83
@ BrainSlugs83 tak tahu Saya menggunakan IDEA, gerhana tidak benar-benar digunakan sebelumnya. Bukankan itu jenis yang tepat untuk Anda? Saya sudah terbiasa dengan c # / visual studio / resharper yang seperti IDEA kecuali benar-benar berfungsi dengan baik! Di semua jetbrains, Anda dapat menekan alt-enter untuk mendapatkan daftar saran ketika ada kesalahan - jadi ketik pengaturan untuk int memperkenalkan kesalahan Anda bisa alt-enter on dan membuatnya untuk menyortir jenisnya
JonnyRaa
5

Anda bisa melihat ke Kotlin dengan JetBrains, tapi ini val. bukan var.

Artiom
sumber
4
Kotlin memiliki val dan var. val sama dengan mendeklarasikan variabel final dalam java, var memungkinkan penugasan kembali.
samlewis
5

Java 10 memang mendapatkan inferensi tipe variabel lokal, jadi sekarang ia memiliki varyang cukup banyak setara dengan C # satu (sejauh yang saya tahu).

Hal ini juga dapat menyimpulkan jenis non-denotable (jenis yang tidak bisa diberi nama di tempat itu oleh programmer; meskipun yang jenis non-denotable berbeda). Lihat misalnya Trik dengan vardan kelas anonim (yang tidak boleh Anda gunakan di tempat kerja) .

Satu perbedaan yang saya dapat temukan adalah bahwa di C #,

Jika jenis bernama var berada dalam ruang lingkup, maka kata kunci var akan memutuskan untuk nama tipe itu dan tidak akan diperlakukan sebagai bagian dari deklarasi variabel lokal yang diketik secara implisit.

Di Jawa 10 varbukan nama jenis hukum.

Alexey Romanov
sumber
@ Lii Ya, saya tidak ingat apa yang saya maksud di sini, dihapus.
Alexey Romanov
Bagus! Akan menghapus komentar saya untuk membersihkan sejarah!
Lii
4

Sebagai Jawa 10, setara adalah ... var.

Brian Goetz
sumber
Apakah ada setiap perbedaan? Maksud saya, Anda tahu lebih baik daripada menulis jawaban pendek seperti ini, bagaimana dengan tingkat perwakilan Anda dan semua. Dan tentunya harus ada beberapa perbedaan.
user1306322
@ user1306322 Itu pertanyaan yang sepenuhnya terpisah! Anda mungkin memeriksa tag java-10, karena banyak aspek dari ini telah ditanyakan.
Brian Goetz
Nah, ini yang bersangkutan untuk melihat jika Anda googling ini, karena dilengkapi pertama dan terkait dalam setiap pos terkait di sidebar. Jadi saya kira jika Anda tahu pertanyaan terpisah yang menjawabnya, Anda mungkin dapat setidaknya menghubungkannya atau memasukkan sebagiannya ke dalam jawaban Anda.
user1306322
3

Saya tahu ini lebih tua tetapi mengapa tidak membuat kelas var dan membuat konstruktor dengan tipe yang berbeda dan tergantung pada konstruktor yang dipanggil, Anda dapat var dengan tipe yang berbeda. Anda bahkan dapat membangun metode untuk mengonversi satu jenis ke jenis lainnya.

Sebastian Zaba
sumber
3

Lombokmendukung var tetapi masih diklasifikasikan sebagai percobaan:

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);

Inilah jebakan yang harus dihindari ketika mencoba menggunakannya IntelliJ IDEA. Tampaknya berfungsi seperti yang diharapkan meskipun termasuk penyelesaian otomatis dan segalanya. Sampai ada solusi "non-hacky" (misalnya karena JEP 286: Inferensi Tipe Variabel Lokal ), ini mungkin taruhan terbaik Anda saat ini.

Catatan yang valdidukung Lombokjuga tanpa mengubah atau membuat lombok.config.

BullyWiiPlaza
sumber
2

Anda bisa, dalam Java 10, tetapi hanya untuk variabel lokal , yang berarti,

Kamu bisa,

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

Tapi tidak bisa,

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

Lihat spesifikasi untuk info lebih lanjut.

Antho Christen
sumber
2
Ini salah. vardapat digunakan untuk berbagai bentuk tipe yang tidak dapat didenotasikan, termasuk tipe penangkapan, tipe persimpangan, dan tipe kelas anonim. Dan, pada Java 11, ini juga dapat diterapkan pada parameter lambda.
Brian Goetz
0

Secara umum Anda dapat menggunakan kelas Object untuk semua tipe, tetapi Anda harus melakukan casting tipe nanti!

misalnya:-

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 Kumar
sumber
Aditya, silakan periksa semua jawaban Anda yang lain. Banyak dari mereka memiliki -1 dan mungkin karena alasan yang bagus. Jangan hanya memposting apa pun jika Anda tidak yakin itu benar.
user1306322
@ user1306322 apa masalahnya dalam jawaban saya! bisakah kamu menguraikan? tidak bisakah kita menggunakan kelas Objek untuk semua tipe data?
Aditya Kumar
Objek objek = 12; Object object1 = "Aditya"; Objek objek2 = 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
Masalahnya adalah Anda tidak mengerti pertanyaannya. Pertanyaannya bukan "bagaimana membuat ini berhasil", tetapi "adakah yang seperti ini". Anda menjawab pertanyaan yang salah. Dengan varkata sekarang secara resmi dalam bahasa, jawaban Anda juga mengacu pada cara yang sudah kuno.
user1306322