Jaki jest odpowiednik słowa kluczowego C # „var” w Javie?

264

Jednym zastosowaniem słowa kluczowego var w języku C # jest niejawna deklaracja typu. Jaka jest równoważna składnia Java dla var ?

Arturo
źródło
4
val(lub var) jeśli używasz określonego języka „zastępowania Java” ;-)
6
@pst: to byłby Scala? Hm tak jest.
rsenna
W przypadku IntelliJ przesłałem to jako żądanie funkcji: youtrack.jetbrains.com/issue/IDEA-102808 IDE może zwinąć kod, aby pokazać val lub var, nawet jeśli kod źródłowy go nie ma.
Jon Onstott,
@ Jon Zhakowałem coś razem dla IntelliJ, zobacz moją odpowiedź .
balpha
3
Jest teraz propozycja włączenia tej funkcji do Java - openjdk.java.net/jeps/286
McGin

Odpowiedzi:

248

Nie ma żadnego. Niestety, musisz wpisać pełną nazwę typu.

Edycja: 7 lat po opublikowaniu varw Javie 10 dodano wnioskowanie o zmiennych lokalnych (z ).

Edycja: 6 lat po opublikowaniu, aby zebrać niektóre komentarze poniżej:

  • Powodem, dla którego C # zawiera to varsłowo kluczowe, jest to, że można mieć typy, które nie mają nazwy w .NET. Na przykład:

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

    W takim przypadku podanie odpowiedniego typu byłoby niemożliwe myData. 6 lat temu było to niemożliwe w Javie (wszystkie typy miały nazwy, nawet jeśli były bardzo gadatliwe i niezdarne). Nie wiem, czy to się zmieniło w międzyczasie.

  • varto nie to samo co dynamic. variables są nadal w 100% typowane statycznie. To nie będzie kompilować:

    var myString = "foo";
    myString = 3;
  • varjest także przydatny, gdy typ jest oczywisty z kontekstu. Na przykład:

    var currentUser = User.GetCurrent();

    Mogę powiedzieć, że w każdym kodzie, za który jestem odpowiedzialny, currentUserma Userklasę pochodną. Oczywiście, jeśli twoja implementacja User.GetCurrentzwraca int, to może to ci szkodzić.

  • Nie ma to nic wspólnego var, ale jeśli masz dziwne hierarchie dziedziczenia, w których metody cieniowane są innymi metodami (np. new public void DoAThing()), Nie zapominaj, że na metody nie-wirtualne ma wpływ typ, w jakim są rzutowane.

    Nie wyobrażam sobie scenariusza z prawdziwego świata, w którym świadczy to o dobrym projekcie, ale może nie działać zgodnie z oczekiwaniami:

    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

    Jak wskazano, nie ma to wpływu na metody wirtualne.

  • Nie, nie ma niezręcznego sposobu na zainicjowanie varzmiennej bez rzeczywistej.

    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

    W takim przypadku po prostu zrób to w staromodny sposób:

    object foo6;
Mike Caron
źródło
11
@Mike Caron: C # ma [domyślne] połączenia niewirtualne, a operatorzy nie są wirtualni, więc ... var p = new X(); p.Z()nie jest taki sam jak SuperX p = new X(); p.Z()dla wszystkich X i SuperX, chociaż X : SuperX. Z vartej statycznej typu od pzawsze jest Xw pierwszym przykładzie powyżej, ale zawsze SuperXw drugim przykładzie. Subtelna, ale ważna różnica, o której należy pamiętać. Ale twoja odpowiedź jest bardzo poprawna :-)
200
@Jon Hanna: varnie wyjaśnia kodu. Wręcz przeciwnie, moim zdaniem. Po co na przykład pisać typ dwa (a nawet trzy) razy w tym samym wierszu, kiedy go deklarujesz i tworzysz jego instancję ( RadioButton radioButton = new RadioButton();)? varsprawia, że ​​myślisz dwa razy, gdy nazywasz zmienne, ponieważ skupia się on na funkcjonalności, a nie na typie (na przykład UserCollection collection = new userRepository.GetUsers();, bardziej naturalnie, zmienia się w var users = userRepository.GetUsers();). Jeśli uważasz, że varjest niejasne, to tylko dlatego, że nie jest do tego przyzwyczajony.
Martin Odhelius,
4
@MartinOdhelius z varcałą pewnością potrafi dobrze wyczyścić kod, ale może też spowodować, że będzie zbyt niejasny; jak wiele opcji formatowania. Saldo różni się w zależności od tego, jak często korzystasz z anonimowych obiektów i rodzajów, z których żaden nie istniał w .NET 1.0, co czyni go mniej użytecznym jako hipotetyczne słowo kluczowe w pierwszej wersji C♯. Nazwałbym tylko RadioButton radioButtonw przypadku metody fabrycznej lub pomocniczej, w której jedyną znaczącą rzeczą w przycisku był fakt, że był to RadioButton, w przeciwnym razie to szaleństwo z lub bez var.
Jon Hanna,
6
@Jon Hanna: Byłem kiedyś tak samo krytyczny varjak ty, jeśli nie bardziej, ale zmieniłem zdanie i być może jest to tak proste, jak kwestia różnych opinii, ponieważ nadal uważam, że się mylisz, kiedy mówisz, że to nieważne, ile używasz anonimowych obiektów i generycznych;) Deklaracja typu najczęściej jest po prostu szumem kodu, jeśli nie możesz zrozumieć kodu bez niego, kod jest prawdopodobnie niejasny w obu przypadkach.
Martin Odhelius,
3
Mylisz var z anonimowymi typami . varsam prosi kompilator o wywnioskowanie typu z przydziału; to cukier syntaktyczny. Na początku byłem sceptyczny, ale używam go religijnie i jeszcze nie spotkałem się z czasem, kiedy to spowodowało zamieszanie. Usuwa nadmiarowość podczas tworzenia instancji i eliminuje potrzebę sprawdzania typu podczas odwoływania się. Nie ma odpowiednika JAVA od JAVA 9.
Robear
46

Jeśli dodasz Lombok do swojego projektu, możesz użyć jego słowa kluczowego val .

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

darthtrevino
źródło
1
@rightfold: Obiekty, do których odniesienia finalnie są koniecznie niezmienne. Zastanów sięfinal StringBuilder strB = new StringBuilder("My reference is final"); strB.append("I'm not immutable");
Matthias Braun
1
Od wersji lombok 1.16.12 istnieje również eksperymentalne wsparcie dla var. projectlombok.org/features/experimental/var.html
Roel Spilker
@MatthiasBraun twój przykład jest zły. W tym przypadku sama klasa StringBuilder jest niezmienna, wystarczy dodać wartość łańcucha do jej wewnętrznej struktury za pomocą metody, jest to całkowicie legalne.
Andzej Maciusovic
27

JEP - Propozycja ulepszenia JDK

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

JEP 286: Wnioskowanie o typie zmiennej lokalnej

Autor Brian Goetz

// Goals:
var list = new ArrayList<String>();  // infers ArrayList<String>
var stream = list.stream();          // infers Stream<String>
blueberry0xff
źródło
Jaka wersja Java? 10?
Peter Mortensen
@PeterMortensen Tak. JEP 286 został zaakceptowany i opublikowany w JDK 10 (patrz 286 w sekcji Funkcje na openjdk.java.net/projects/jdk/10 ).
Justin Albano
20

Przygotowałem wtyczkę dla IntelliJ, która - w pewnym sensie - daje ci varJavę. Jest to hack, więc obowiązują zwykłe zastrzeżenia, ale jeśli używasz IntelliJ do programowania Java i chcesz go wypróbować, znajdziesz go na https://bitbucket.org/balpha/varsity .

balpha
źródło
Byłoby wspaniale mieć skrót klawiszowy do składania / rozwijania typów deklaracji w bieżącym edytorze. Świetna wtyczka.
skrót
2
@hotkey Wykorzystuje wbudowane składanie kodu IntelliJ, dzięki czemu możesz rozwinąć wszystko za pomocą Ctrl-Shift-NumPadPlus. Gdy kursor znajduje się w wierszu zawierającym złożoną deklarację zmiennej, możesz Ctrl-NumPadPlus i Ctrl-NumPadMinus, aby złożyć / rozwinąć deklaracje w bieżącej metodzie. Składanie wszystkich deklaracji jest nieco niewygodne, wszystko składasz (Ctrl-Shift-NumPadMinus), a następnie rozkładasz wszystko ponownie (Ctrl-Shift-NumPadPlus).
balpha
18

Wraz z wydaniem JDK 10 20 marca Java zawiera teraz varnazwę typu zastrzeżonego (nie słowo kluczowe - patrz poniżej), jak określono w JEP 286 . W przypadku zmiennych lokalnych w Java 10 lub nowszej obowiązuje teraz:

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

Nazwa vartypu zarezerwowanego w Javie jest prawie identyczna ze varsłowem kluczowym w języku C #, ponieważ oba pozwalają na niejawne pisanie (ważne różnice poniżej). varw Javie można używać wyłącznie do wnioskowania typu niejawnego w następujących kontekstach (jak wyliczono w JEP 286: Cele ):

  • zmienne lokalne z inicjalizatorami
  • indeksy w rozszerzonej pętli for
  • miejscowi zadeklarowani w tradycyjnej pętli for

Dlatego var nie można go używać do pól, typów zwracanych, nazw klas ani nazw interfejsów. Jego uzasadnieniem jest usunięcie potrzeby dołączania długich nazw typów podczas deklarowania i definiowania zmiennych lokalnych, jak stwierdzono w JEP 286 (autor: Brian Goetz):

Staramy się poprawić wrażenia programistów, zmniejszając ceremonię związaną z pisaniem kodu Java, przy jednoczesnym utrzymaniu zaangażowania Javy w bezpieczeństwo typu statycznego, umożliwiając programistom unikanie często niepotrzebnej manifestacji lokalnych zmiennych.

var Określanie zakresu w Javie

Należy zauważyć, że varnie jest słowem kluczowym w Javie, ale raczej nazwą typu zarezerwowanego. Jak cytowano z JEP 286:

Identyfikator var nie jest słowem kluczowym; zamiast tego jest to nazwa typu zarezerwowanego. Oznacza to, że kod, który używa var jako zmiennej, metody lub nazwy pakietu, nie zostanie zmieniony; wpłynie to na kod, który używa var jako nazwy klasy lub interfejsu (ale nazwy te są rzadkie w praktyce, ponieważ naruszają zwykłe konwencje nazewnictwa).

Należy pamiętać, że ponieważ varjest to nazwa typu zarezerwowanego, a nie słowo kluczowe, nadal można jej używać w nazwach pakietów, nazwach metod i nazwach zmiennych (wraz z nową rolą zakłócania typu). Na przykład następujące są wszystkie przykłady prawidłowego użycia varw Javie:

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

Jak cytowano z JEP 286:

To leczenie byłoby ograniczone do zmiennych lokalnych z inicjalizatorami, indeksów w rozszerzonej pętli for i miejscowych zadeklarowanych w tradycyjnej pętli for; nie byłby dostępny dla formałów metod, konstruktorów, typów zwracanych metod, pól, formałów catch ani innych deklaracji zmiennych.

Różnice między varw Javie i C.

Jest to jedna zauważalna różnica między językami varC # i Java: varmogą być używane jako nazwa typu w języku C #, ale nie mogą być używane jako nazwa klasy lub nazwa interfejsu w języku Java. Zgodnie z dokumentacją w języku C # (niejawnie wpisane zmienne lokalne) :

Jeśli nazwany typ varjest objęty zakresem, varsłowo kluczowe rozpozna nazwę tego typu i nie będzie traktowane jako część niejawnie wpisanej deklaracji zmiennej lokalnej.

Możliwość użycia varjako nazwy typu w języku C # powoduje pewną złożoność i wprowadza pewne skomplikowane reguły rozwiązywania, których można uniknąć varw Javie, uniemożliwiając używanie nazwy varklasy lub interfejsu. Aby uzyskać informacje na temat złożoności varnazw typów w języku C #, zobacz Ograniczenia dotyczą niejawnie deklarowanych zmiennych . Aby uzyskać więcej informacji na temat uzasadnienia decyzji dotyczącej zakresu dla `var w Javie, zobacz JEP 286: Wybory zakresu .

Justin Albano
źródło
Czy jest jakaś różnica między Javą i C #, której nie można użyć vardo pól lub typów zwracanych? Dlaczego warto to zauważyć?
user1306322
@ user1306322 W tym kontekście nr. varw Javie nie można używać dla pól ani typów zwracanych. Jest to ważne, ponieważ to ograniczenie varuwarunkowane jest kontekstem, gdzie można go używać tylko w niektórych kontekstach (zmienne lokalne), a nie w innych. Należy zauważyć, że niekoniecznie jest to różnica między Javą i C #, ale ogólnie ważne ograniczenie przy korzystaniu varz Java.
Justin Albano
Właśnie spojrzałem w górę i wygląda na to, że w c # możesz stworzyć varnazwę klasy i używać jej jako takiej. Technicznie jest to „kontekstowe słowo kluczowe” w przypadku c #, ale w Javie wydaje się, że nie można zrobić tego samego. Popraw mnie, jeśli się mylę.
user1306322
1
Masz rację. Nie można używać varjako nazwy klasy lub nazwy interfejsu w Javie (co zresztą i tak nie jest powszechne), ale można go używać do nazw zmiennych, nazw metod i nazw pakietów. Na przykład, var var = 1;to ważne stwierdzenie Java ale próbuje zadeklarować klasę jako public class var {}powoduje błąd: as of release 10, 'var' is a restricted local variable type and cannot be used for type declarations. Zaktualizowałem powyższą odpowiedź, aby uzyskać bardziej szczegółowe informacje na temat uzasadnienia varw Javie i jej różnic varw stosunku do C #.
Justin Albano
11

Będzie obsługiwany w JDK 10. Można go nawet zobaczyć w działaniu w kompilacji wczesnego dostępu .

JEP 286 :

Ulepsz język Java, aby rozszerzyć wnioskowanie o typ na deklaracje zmiennych lokalnych za pomocą inicjatorów.

Więc teraz zamiast pisać:

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

Ty piszesz:

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

Uwagi:

  • varjest teraz nazwą typu zarezerwowanego
  • Java jest nadal zobowiązana do pisania statycznego!
  • Można go używać tylko w deklaracjach zmiennych lokalnych

Jeśli chcesz spróbować bez instalacji Java w systemie lokalnym, stworzyłem obraz Docker z zainstalowanym JDK 10:

$ 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
źródło
3
Uwaga: podany kod (przed / po var) nie jest równoważny. W tym varprzykładzie listjest typu ArrayList, a nie a List.
Gili
8

Prostym rozwiązaniem (zakładając, że używasz przyzwoitego IDE) jest wpisanie wszędzie „int”, a następnie ustawienie go dla Ciebie.

Właśnie dodałem klasę o nazwie „var”, więc nie muszę wpisywać czegoś innego.

Kod jest wciąż zbyt szczegółowy, ale przynajmniej nie musisz go pisać!

JonnyRaa
źródło
Kiedy mówisz, że „przyzwoite IDE” jest wykluczone Eclipse *? - wydaje się, że to nie działa w Lunie (przynajmniej kiedy właśnie tego spróbowałem int) - czy coś mi brakuje? (*: chociaż nigdy nie nazwałbym Eclipse porządnym IDE, nie mogę oceniać innych ...)
BrainSlugs83
@ BrainSlugs83 dunno Używam IDEA, tak naprawdę wcześniej nie używałem zaćmienia. Czy to nie poprawia typów dla ciebie? Jestem przyzwyczajony do c # / visual studio / resharper, który jest podobny do IDEA, ale faktycznie działa poprawnie! We wszystkich odrzutowcach możesz nacisnąć Alt-Enter, aby uzyskać listę sugestii, gdy wystąpi błąd - więc ustawienie type na int wprowadza błąd, który możesz Alt-Enter i
sprawi,
5

Możesz zajrzeć do Kotlin przez JetBrains, ale to jest val. nie var.

Artiom
źródło
4
Kotlin ma val i var. val jest równoważne z deklarowaniem zmiennej finalnej w java, var umożliwia zmianę przypisania.
samlewis
5

Java 10 uzyskała wnioskowanie na temat lokalnych zmiennych, więc teraz ma varprawie odpowiednik C # one (o ile mi wiadomo).

Może również wywnioskować non-denotable rodzajów (typów, które nie mogą być nazwane w tym miejscu przez programistę, choć których typy są non-denotable jest inna). Zobacz np. Sztuczki vari anonimowe zajęcia (których nigdy nie powinieneś używać w pracy) .

Jedną różnicą, którą mogłem znaleźć, jest to, że w C #

Jeśli typ o nazwie var znajduje się w zakresie, słowo kluczowe var rozpozna nazwę tego typu i nie będzie traktowane jako część niejawnie wpisanej deklaracji zmiennej lokalnej.

W Javie 10 varnie jest prawidłową nazwą typu.

Aleksiej Romanow
źródło
@Lii Tak, nie pamiętam o co mi tutaj chodziło, usunięto.
Aleksiej Romanow
Wspaniały! Usunie mój komentarz, aby wyczyścić historię!
Lii
4

Jak Java 10, odpowiednikiem jest ... var.

Brian Goetz
źródło
Czy są jakieś różnice? Mam na myśli, że wiesz lepiej niż pisać takie krótkie odpowiedzi, co z twoim poziomem powtórzeń n wszystkim. I na pewno muszą być pewne różnice.
user1306322
@ user1306322 To całkowicie osobne pytanie! Możesz sprawdzić tag java-10, ponieważ wiele aspektów tego zostało już zadanych.
Brian Goetz
Cóż, to jest pytanie patrzeć jeśli googlowania tego, jak to jest na pierwszym miejscu i jest związany w każdym powiązanym wątku na pasku bocznym. Tak więc przypuszczam, że jeśli znasz to oddzielne pytanie, które na nie odpowiada, być może będziesz w stanie przynajmniej link do niego lub dołączyć jego część do swojej odpowiedzi.
user1306322
3

Wiem, że jest to starsze, ale dlaczego nie stworzyć klasy var i stworzyć konstruktorów z różnymi typami, a zależnie od tego, który konstruktor zostanie wywołany, otrzymasz var z innym typem. Możesz nawet wbudować metody konwersji jednego typu na inny.

Sebastian Zaba
źródło
3

Lombokobsługuje var, ale nadal jest klasyfikowany jako eksperymentalny:

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

Oto pułapka, której należy unikać, próbując jej użyć IntelliJ IDEA. Wygląda na to, że działa zgodnie z oczekiwaniami, włączając automatyczne uzupełnianie i wszystko. Dopóki nie będzie rozwiązania „niehakującego” (np. Z powodu JEP 286: Lokalne wnioskowanie o typ zmiennej ), może to być teraz najlepszy wybór.

Pamiętaj, że valjest to również wsparcie Lombokbez modyfikowania ani tworzenia lombok.config.

BullyWiiPlaza
źródło
2

Możesz w Javie 10, ale tylko dla zmiennych lokalnych , co oznacza,

Możesz,

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

Ale nie mogę

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

Sprawdź specyfikację, aby uzyskać więcej informacji.

Antho Christen
źródło
2
To jest niepoprawne. varmoże być używany do wielu form typów nieoznaczalnych, w tym typów przechwytywania, typów skrzyżowań i typów anonimowych. Od wersji Java 11 można go również stosować do parametrów lambda.
Brian Goetz
0

Zasadniczo możesz używać klasy Object dla dowolnego typu, ale później możesz rzutować!

na przykład:-

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
źródło
Aditya, sprawdź wszystkie pozostałe odpowiedzi. Wiele z nich ma -1 i prawdopodobnie nie bez powodu. Nie publikuj niczego, jeśli nie masz pewności, czy jest to poprawne.
user1306322
@ user1306322 jaki jest problem w mojej odpowiedzi! możesz opracować? czy nie możemy użyć klasy Object dla wszystkich typów danych?
Aditya Kumar
Obiekt obiektu = 12; Obiekt object1 = "Aditya"; Obiekt 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
Problem polega na tym, że nie zrozumiałeś pytania. Pytanie nie brzmiało „jak sprawić, by to działało”, ale „czy jest coś takiego”. Odpowiadasz na złe pytanie. Ponieważ varsłowo jest teraz oficjalnie w języku, twoja odpowiedź odnosi się również do starego stylu.
user1306322