Qual è l'equivalente della parola chiave C # 'var' in Java?


264

Un uso della parola chiave var in C # è la dichiarazione di tipo implicito. Qual è la sintassi equivalente Java per var ?


4
val(o var) se si utilizza un particolare linguaggio "sostituzione Java" ;-)

6
@pst: sarebbe Scala? Eh si, lo è.
rsenna,

Per IntelliJ, l'ho inviato come richiesta di funzionalità: youtrack.jetbrains.com/issue/IDEA-102808 L'IDE potrebbe comprimere il codice per mostrare val o var anche se il codice sottostante non lo avrebbe.
Jon Onstott,

@Jon Ho hackerato qualcosa insieme per IntelliJ, vedi la mia risposta .
balpha,

3
Esiste ora una proposta per includere questa funzione in Java - openjdk.java.net/jeps/286
McGin

Risposte:


248

Non c'è nessuno. Purtroppo, devi digitare il nome completo del tipo.

Modifica: 7 anni dopo essere stato pubblicato, l'inferenza del tipo per le variabili locali (con var) è stata aggiunta in Java 10.

Modifica: 6 anni dopo la pubblicazione, per raccogliere alcuni dei commenti dal basso:

  • Il motivo per cui C # ha la varparola chiave è perché è possibile avere tipi senza nome in .NET. Per esempio:

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

    In questo caso, sarebbe impossibile dare un tipo adeguato a myData. 6 anni fa, questo era impossibile in Java (tutti i tipi avevano nomi, anche se erano estremamente dettagliati e irti). Non so se questo sia cambiato nel frattempo.

  • varnon è lo stesso di dynamic. varI numeri sono ancora digitati staticamente al 100%. Questo non compilerà:

    var myString = "foo";
    myString = 3;
  • varè utile anche quando il tipo è evidente dal contesto. Per esempio:

    var currentUser = User.GetCurrent();

    Posso dire che in qualsiasi codice di cui sono responsabile, currentUser contiene una Userclasse derivata o. Ovviamente, se la tua implementazione di User.GetCurrentreturn an int, allora forse questo è un danno per te.

  • Questo non ha nulla a che fare con var, ma se si hanno strane gerarchie ereditarie in cui si ombreggiano i metodi con altri metodi (ad esempio new public void DoAThing()), non dimenticare che i metodi non virtuali sono influenzati dal Tipo in cui vengono espressi.

    Non riesco a immaginare uno scenario del mondo reale in cui questo sia indicativo di un buon design, ma potrebbe non funzionare come previsto:

    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

    Come indicato, i metodi virtuali non sono interessati da questo.

  • No, non esiste un modo non semplice per inizializzare un varsenza una variabile effettiva.

    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

    In questo caso, fallo alla vecchia maniera:

    object foo6;

11
@Mike Caron: C # ha [default] chiamate non virtuali e gli operatori non sono virtuali quindi ... var p = new X(); p.Z()non è lo stesso SuperX p = new X(); p.Z()di tutte le X e e SuperX, anche se X : SuperX. Convar il tipo statico di pè sempre Xnel primo esempio sopra, ma sempre SuperXnel secondo esempio. Una differenza sottile ma importante da tenere presente. Ma la tua risposta è molto corretta :-)

200
@Jon Hanna: varnon rende il codice meno chiaro. Piuttosto il contrario secondo me. Perché ad esempio scrivere il tipo due (o anche tre) volte sulla stessa riga quando lo si dichiara e si crea un'istanza ( RadioButton radioButton = new RadioButton();)? varti fa piuttosto pensare due volte quando dai un nome alle tue variabili perché focalizza l'attenzione sulla funzionalità piuttosto che sul tipo (ad esempio, UserCollection collection = new userRepository.GetUsers();piuttosto più naturalmente si trasforma in var users = userRepository.GetUsers();). Se pensi che varnon sia chiaro, è solo perché inutilizzato.
Martin Odhelius,

4
@MartinOdhelius var può sicuramente rendere chiaro il codice usato bene, ma può anche renderlo poco chiaro troppo usato male; come molte opzioni di formattazione. Il saldo differisce a seconda di quanto usi oggetti anonimi e generici, nessuno dei quali esisteva in .NET 1.0, rendendolo meno utile come parola chiave ipotetica nella prima versione di C♯. Vorrei solo nominare a RadioButton radioButtonnel caso di un metodo factory o helper in cui l'unica cosa significativa del pulsante era che era un RadioButton, altrimenti è una follia con o senza var.
Jon Hanna,

6
@Jon Hanna: una volta sono stato critico varcome te, se non di più, ma ho cambiato la mia opinione, e forse è semplice come una domanda di opinioni diverse, perché penso ancora che ti sbagli quando dici che è un importa quanto stai usando oggetti anonimi e generici;) La dichiarazione del tipo è spesso solo rumore del codice, se non riesci a capire il codice senza di esso il codice probabilmente non è chiaro in entrambi i casi.
Martin Odhelius,

3
Stai confondendo var con tipi anonimi . varstesso richiede semplicemente al compilatore di dedurre il tipo dall'assegnazione; è zucchero sintattico. All'inizio ero scettico, ma lo uso religiosamente e devo ancora incontrare un momento in cui ha causato confusione. Rimuove la ridondanza durante l'istanza e rimuove la necessità di controllare il tipo quando si fa riferimento. Non esiste un equivalente JAVA al JAVA 9.
Robear

46

Se aggiungi Lombok al tuo progetto puoi usare la sua parola chiave val .

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


1
@rightfold: oggetti il ​​cui riferimento è finalnon necessariamente immutabile. Considerafinal StringBuilder strB = new StringBuilder("My reference is final"); strB.append("I'm not immutable");
Matthias Braun il

1
Da lombok v1.16.12 esiste anche un supporto sperimentale per var. projectlombok.org/features/experimental/var.html
Roel Spilker

@MatthiasBraun il tuo esempio è sbagliato. In questo caso la classe StringBuilder stessa è immutabile, basta aggiungere il valore di stringa alla sua struttura interna usando il metodo, questo è totalmente legale.
Andzej Maciusovic,


20

Ho preparato un plugin per IntelliJ che, in un certo senso, ti dà varin Java. È un trucco, quindi si applicano le solite dichiarazioni di non responsabilità, ma se usi IntelliJ per il tuo sviluppo Java e vuoi provarlo, è su https://bitbucket.org/balpha/varsity .


Sarebbe bello avere una scorciatoia da tastiera per piegare / aprire i tipi di dichiarazione nell'editor corrente. Ottimo plugin però.
tasto di scelta rapida

2
@hotkey Utilizza la piegatura del codice integrata di IntelliJ, in modo da poter dispiegare tutto con Ctrl-Shift-NumPadPlus. Quando il cursore si trova su una riga che contiene una dichiarazione di variabile piegata, è possibile Ctrl-NumPadPlus e Ctrl-NumPadMinus per piegare / aprire le dichiarazioni nel metodo corrente. Piegare tutte le dichiarazioni è un po 'imbarazzante, hai piegato tutto (Ctrl-Shift-NumPadMinus) e poi spiegato di nuovo tutto (Ctrl-Shift-NumPadPlus).
balpha,

18

Con il rilascio di JDK 10 il 20 marzo, Java ora include un varnome di tipo riservato (non una parola chiave, vedere di seguito) come specificato in JEP 286 . Per le variabili locali, ora è valido in Java 10 o versioni successive:

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

Il varnome del tipo riservato in Java è quasi identico alla varparola chiave in C # in quanto entrambi consentono una digitazione implicita (vedi sotto per differenze importanti). varin Java può essere utilizzato solo per l'inferenza di tipo implicito nei seguenti contesti (come elencato in JEP 286: Obiettivi ):

  • variabili locali con inizializzatori
  • indici nel for-loop avanzato
  • gente del posto dichiarata in un tradizionale for-loop

Pertanto var non può essere utilizzato per campi, tipi restituiti, nomi di classe o nomi di interfaccia. La sua logica è quella di eliminare la necessità di includere nomi di tipo lunghi quando si dichiarano e si definiscono variabili locali, come affermato in JEP 286 (scritto da Brian Goetz):

Cerchiamo di migliorare l'esperienza degli sviluppatori riducendo la cerimonia associata alla scrittura del codice Java, pur mantenendo l'impegno di Java per la sicurezza dei tipi statici, consentendo agli sviluppatori di eludere la dichiarazione manifest spesso non necessaria di tipi di variabili locali.

var Scoping in Java

Va notato che varnon è una parola chiave in Java, ma piuttosto un nome di tipo riservato. Come citato da JEP 286:

L'identificatore var non è una parola chiave; invece è un nome di tipo riservato. Ciò significa che il codice che utilizza var come variabile, metodo o nome del pacchetto non sarà interessato; il codice che utilizza var come nome della classe o dell'interfaccia sarà interessato (ma questi nomi sono rari in pratica, poiché violano le convenzioni di denominazione normali).

Si noti che poiché varè un nome di tipo riservato e non una parola chiave, può ancora essere utilizzato per nomi di pacchetti, nomi di metodi e nomi di variabili (insieme al nuovo ruolo di interferenza del tipo). Ad esempio, i seguenti sono tutti esempi di usi validi di varin Java:

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

Come citato da JEP 286:

Questo trattamento sarebbe limitato alle variabili locali con inizializzatori, indici nel for-loop avanzato e locali dichiarati in un for-loop tradizionale; non sarebbe disponibile per formali di metodi, formali di costruttori, tipi di restituzione di metodi, campi, formali di cattura o qualsiasi altro tipo di dichiarazione variabile.

Differenze tra varJava e C.

Questa è una notevole differenza tra varin C # e Java include quanto segue: varpuò essere usato come nome di tipo in C # ma non può essere usato come nome di classe o nome di interfaccia in Java. Secondo la documentazione C # (Variabili locali tipizzate implicitamente) :

Se un tipo denominato varrientra nell'ambito, la varparola chiave si risolverà in quel nome di tipo e non verrà trattata come parte di una dichiarazione di variabile locale tipizzata in modo implicito.

La possibilità di utilizzare varcome nome di tipo in C # crea una certa complessità e introduce alcune regole di risoluzione complesse, che vengono evitate varin Java impedendo varcome nome di classe o di interfaccia. Per informazioni sulla complessità dei varnomi dei tipi in C #, vedere Le restrizioni si applicano alle dichiarazioni di variabili tipizzate in modo implicito . Per ulteriori informazioni sulla logica alla base della decisione di scoping per `var in Java, vedere JEP 286: Scelte di scoping .


C'è qualche differenza tra Java e c # che non è possibile utilizzare varper i campi o i tipi restituiti? Perché è importante notare?
user1306322

@ user1306322 In quel contesto, no. varin Java non può essere utilizzato per campi o tipi restituiti. Questo è importante perché questa limitazione rende varsensibile al contesto, dove può essere utilizzata solo in alcuni contesti (variabili locali) e non in altri. Questa non è necessariamente una differenza tra Java e C # che dovrebbe essere notato, ma un'importante restrizione in generale quando si usa varin Java.
Justin Albano,

Ho appena cercato e sembra che in c # puoi creare varun nome di classe e usarlo come tale. Tecnicamente è una "parola chiave di contesto" in caso di c #, ma in Java sembra che tu non possa fare lo stesso. Correggimi se sbaglio.
user1306322

1
Hai ragione. Non è possibile utilizzare varcome nome di classe o nome di interfaccia in Java (che non è comunque comune), ma è possibile utilizzarlo per nomi di variabili, nomi di metodi e nomi di pacchetti. Ad esempio, var var = 1;è una dichiarazione valida Java ma cercando di dichiarare una classe come public class var {}si traduce in un errore: as of release 10, 'var' is a restricted local variable type and cannot be used for type declarations. Ho aggiornato la risposta sopra per approfondire la logica alla base vardi Java e le sue differenze con varin C #.
Justin Albano,

11

Sarà supportato in JDK 10. È anche possibile vederlo in azione nella build di accesso anticipato .

Il JEP 286 :

Migliora il linguaggio Java per estendere l'inferenza del tipo alle dichiarazioni delle variabili locali con gli inizializzatori.

Quindi ora invece di scrivere:

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

Scrivi:

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

Appunti:

  • var è ora a nome di tipo riservato
  • Java è fermo impegnato nella tipizzazione statica!
  • Può essere utilizzato solo nelle dichiarazioni delle variabili locali

Se vuoi provarlo senza installare Java sul tuo sistema locale, ho creato un'immagine Docker con JDK 10 installato su di esso:

$ 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
Attenzione, il codice fornito (prima / dopo var) non è equivalente. Nel varesempio listè di tipo ArrayList, non una List.
Gili,

8

Una soluzione semplice (supponendo che tu stia utilizzando un IDE decente) è semplicemente digitare 'int' ovunque e quindi farlo impostare per te.

In realtà ho appena aggiunto una classe chiamata 'var', quindi non devo digitare qualcosa di diverso.

Il codice è ancora troppo dettagliato, ma almeno non devi scriverlo!


Quando dici "IDE decente" è escluso Eclipse *? - questo non sembra funzionare in Luna (almeno quando l'ho appena provato int) - Mi sto perdendo qualcosa? (*: mentre non definirei mai Eclipse un IDE decente, non posso giudicare per gli altri ...)
BrainSlugs83

@ BrainSlugs83 non so che sto usando IDEA, non ho usato eclissi prima. Non corregge i tipi per te? Sono abituato a c # / visual studio / resharper che è come IDEA tranne che in realtà funziona correttamente! In tutti i jetbrain puoi premere alt-invio per ottenere un elenco di suggerimenti in caso di errore, quindi l'impostazione del tipo su int introduce un errore che puoi inserire e ottenere per ordinare il tipo
JonnyRaa

5

Puoi dare un'occhiata a Kotlin di JetBrains, ma è val. non var.


4
Kotlin ha val e var. val equivale a dichiarare un finale variabile in java, var consente la riassegnazione.
Samlew è il

5

Java 10 ha ottenuto l'inferenza del tipo di variabile locale, quindi ora ha var praticamente l'equivalente di C # one (per quanto ne so).

Può anche inferire tipi non denotabili (tipi che non possono essere nominati in quel posto dal programmatore; anche se quali tipi non sono denotabili è diverso). Vedi ad esempio Trucchi con vare classi anonime (che non dovresti mai usare al lavoro) .

L'unica differenza che ho trovato è che in C #,

Se un tipo denominato var è nell'ambito, la parola chiave var si risolverà in quel nome di tipo e non verrà trattata come parte di una dichiarazione di variabile locale tipizzata in modo implicito.

In Java 10 varnon è un nome di tipo legale.


@Lii Sì, non ricordo cosa intendevo qui, rimosso.
Alexey Romanov,

Grande! Rimuoverò il mio commento per ripulire la cronologia!
Lii

4

Come di Java 10, l'equivalente è ... var.


Ci sono delle differenze? Voglio dire, lo sai meglio che scrivere brevi risposte come questa, con il tuo livello di rep n tutto. E sicuramente ci devono essere alcune differenze.
user1306322

@ user1306322 Questa è una domanda completamente separata! È possibile controllare il tag java-10, poiché molti aspetti di questo sono già stati richiesti.
Brian Goetz,

Bene, questa è la domanda da considerare se stai cercando su Google, come viene prima ed è collegata in ogni post correlato nella barra laterale. Quindi suppongo che se conosci quella domanda separata che ti risponde, potresti essere in grado almeno di collegarti ad essa o di includere parti di essa nella tua risposta.
user1306322

3

So che questo è più vecchio, ma perché non creare una classe var e creare costruttori con tipi diversi e in base a quali costruttori viene invocato si ottiene var con tipo diverso. Potresti persino creare metodi per convertire un tipo in un altro.


3

Lomboksupporta var ma è ancora classificato come sperimentale:

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

Ecco una trappola da evitare quando si tenta di utilizzarlo IntelliJ IDEA. Sembra funzionare come previsto sebbene includa il completamento automatico e tutto. Fino a quando non esiste una soluzione "non confusa" (ad es. Dovuta a JEP 286: Inferenza di tipo variabile locale ), questa potrebbe essere la soluzione migliore in questo momento.

Si noti che valè anche il supporto Lomboksenza modificare o creare un lombok.config.


2

Puoi, in Java 10, ma solo per Local variabili , che significa,

Puoi,

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

Ma non posso

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

Controlla le specifiche per maggiori informazioni.


2
Questo non è corretto varpuò essere utilizzato per molte forme di tipi non identificabili, inclusi tipi di acquisizione, tipi di intersezione e tipi di classe anonimi. E, a partire da Java 11, può essere applicato anche ai parametri lambda.
Brian Goetz,

0

In generale puoi usare la classe Object per qualsiasi tipo, ma devi eseguire il cast del tipo in seguito!

per esempio:-

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, controlla tutte le altre risposte. Molti di loro hanno -1 e probabilmente per una buona ragione. Non pubblicare qualsiasi cosa se non sei sicuro che sia corretto.
user1306322

@ user1306322 qual è il problema nella mia risposta! puoi elaborare? non possiamo usare la classe Object per tutti i tipi di dati?
Aditya Kumar,

Oggetto oggetto = 12; Object object1 = "Aditya"; Oggetto 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,

Il problema è che non hai capito la domanda. La domanda non era "come farlo funzionare", ma "esiste una cosa del genere". Rispondi alla domanda sbagliata. Con la varparola ora ufficialmente nella lingua, la tua risposta si riferisce anche al modo ormai vecchio stile.
user1306322

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.