Was entspricht dem Schlüsselwort C # 'var' in Java?


264

Eine Verwendung des Schlüsselworts var in C # ist die implizite Typdeklaration. Was ist die Java-äquivalente Syntax für var ?


4
val(oder var) wenn Sie eine bestimmte "Java-Ersatz" -Sprache verwenden ;-)

6
@pst: das wäre Scala? Hm ja, das ist es.
Rsenna

Für IntelliJ habe ich dies als Funktionsanforderung gesendet : youtrack.jetbrains.com/issue/IDEA-102808 Die IDE könnte Code reduzieren , um val oder var anzuzeigen , obwohl der zugrunde liegende Code ihn nicht haben würde.
Jon Onstott

@ Jon Ich habe etwas für IntelliJ zusammen gehackt, siehe meine Antwort .
Balpha

3
Es gibt jetzt einen Vorschlag für diese Funktion in Java enthalten - openjdk.java.net/jeps/286
McGin

Antworten:


248

Da ist gar nichts. Leider müssen Sie den vollständigen Typnamen eingeben.

Bearbeiten: 7 Jahre nach der Veröffentlichung varwurde in Java 10 eine Typinferenz für lokale Variablen (mit ) hinzugefügt.

Bearbeiten: 6 Jahre nach dem Posten, um einige der Kommentare von unten zu sammeln:

  • Der Grund, warum C # das varSchlüsselwort hat, ist, dass es möglich ist, Typen zu haben, die in .NET keinen Namen haben. Z.B:

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

    In diesem Fall wäre es unmöglich, einen geeigneten Typ anzugeben myData. Vor 6 Jahren war dies in Java unmöglich (alle Typen hatten Namen, auch wenn sie extrem ausführlich und unfreundlich waren). Ich weiß nicht, ob sich dies inzwischen geändert hat.

  • varist nicht dasselbe wie dynamic. variables sind immer noch zu 100% statisch typisiert. Dies wird nicht kompiliert:

    var myString = "foo";
    myString = 3;
  • varist auch nützlich, wenn der Typ aus dem Kontext ersichtlich ist. Beispielsweise:

    var currentUser = User.GetCurrent();

    Ich kann sagen, dass in jedem Code, für den ich verantwortlich bin, currentUsereine Useroder eine abgeleitete Klasse enthalten ist. Wenn Ihre Implementierung von User.GetCurrentreturn an int ist, ist dies möglicherweise ein Nachteil für Sie.

  • Dies hat nichts damit zu tun var, aber wenn Sie seltsame Vererbungshierarchien haben, in denen Sie Methoden mit anderen Methoden (z. B. new public void DoAThing()) beschatten , vergessen Sie nicht, dass nicht virtuelle Methoden von dem Typ betroffen sind, als den sie umgewandelt werden.

    Ich kann mir kein reales Szenario vorstellen, in dem dies auf gutes Design hinweist, aber dies funktioniert möglicherweise nicht wie erwartet:

    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

    Wie bereits erwähnt, sind virtuelle Methoden davon nicht betroffen.

  • Nein, es gibt keine ungeschickte Möglichkeit, a varohne eine tatsächliche Variable zu initialisieren .

    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 diesem Fall machen Sie es einfach auf die altmodische Weise:

    object foo6;

11
@ Mike Caron: C # hat [Standard] nicht virtuelle Anrufe und Operatoren sind nicht virtuell, also ... var p = new X(); p.Z()ist nicht dasselbe wie SuperX p = new X(); p.Z()für alle X und und SuperX, obwohl X : SuperX. Mit vardem statischen Typ psteht immer Xim ersten Beispiel oben, aber immer SuperXim zweiten Beispiel. Ein subtiler, aber wichtiger Unterschied, den man beachten muss. Aber deine Antwort ist sehr richtig :-)

200
@ Jon Hanna: varmacht den Code nicht weniger klar. Eher das Gegenteil meiner Meinung nach. Warum schreiben Sie den Typ beispielsweise zwei (oder sogar drei) Mal in dieselbe Zeile, wenn Sie ihn deklarieren und instanziieren ( RadioButton radioButton = new RadioButton();)? varlässt Sie beim Benennen Ihrer Variablen eher zweimal überlegen, da der Fokus eher auf der Funktionalität als auf dem Typ liegt (zum Beispiel UserCollection collection = new userRepository.GetUsers();eher natürlich var users = userRepository.GetUsers();). Wenn Sie denken, varist unklar, ist es nur, weil es nicht daran gewöhnt ist.
Martin Odhelius

4
@MartinOdhelius varkann definitiv klar machen, dass Code gut verwendet wird, aber es kann auch unklar machen, ob er zu schlecht verwendet wird. wie viele Formatierungsoptionen. Das Gleichgewicht hängt davon ab, wie oft Sie anonyme Objekte und Generika verwenden, von denen keines in .NET 1.0 vorhanden war. Dies macht es als hypothetisches Schlüsselwort in der ersten Version von C♯ weniger nützlich. Ich würde a nur RadioButton radioButtonim Fall einer Fabrik- oder Hilfsmethode nennen, bei der das einzige, was an dem Knopf von Bedeutung war, war, dass es ein war RadioButton, sonst ist das Wahnsinn mit oder ohne var.
Jon Hanna

6
@ Jon Hanna: Ich war einmal genauso kritisch varwie Sie, wenn nicht mehr, aber ich habe meine Meinung geändert, und vielleicht ist es so einfach wie eine Frage unterschiedlicher Meinungen, weil ich immer noch denke, dass Sie falsch liegen, wenn Sie sagen, dass es eine ist egal wie oft Sie anonyme Objekte und Generika verwenden;) Die Typdeklaration ist meistens nur Code-Rauschen. Wenn Sie den Code ohne ihn nicht verstehen können, ist der Code wahrscheinlich in beiden Fällen unklar.
Martin Odhelius

3
Sie verwechseln var mit anonymen Typen . varselbst fordert den Compiler einfach auf, den Typ aus der Zuweisung abzuleiten; Es ist syntaktischer Zucker. Anfangs war ich skeptisch, aber ich benutze es religiös und habe noch keine Zeit erlebt, in der es Verwirrung stiftete. Es beseitigt Redundanz beim Instanziieren und macht es überflüssig, den Typ beim Referenzieren zu überprüfen. Es gibt kein JAVA-Äquivalent ab JAVA 9.
Robear

46

Wenn Sie Ihrem Projekt Lombok hinzufügen, können Sie dessen Schlüsselwort val verwenden .

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


1
@rightfold: Objekte, deren Referenz ist, finalsind nicht unbedingt unveränderlich. Betrachten Siefinal StringBuilder strB = new StringBuilder("My reference is final"); strB.append("I'm not immutable");
Matthias Braun

1
Seit lombok v1.16.12 gibt es auch experimentelle Unterstützung für var. projectlombok.org/features/experimental/var.html
Roel Spilker

@MatthiasBraun dein Beispiel ist falsch. In diesem Fall ist die StringBuilder-Klasse selbst unveränderlich. Sie fügen der internen Struktur lediglich mithilfe der Methode einen Zeichenfolgenwert hinzu. Dies ist völlig legal.
Andzej Maciusovic


20

Ich habe ein Plugin für IntelliJ zusammengestellt, das Ihnen varin gewisser Weise Java bietet . Es ist ein Hack, daher gelten die üblichen Haftungsausschlüsse. Wenn Sie jedoch IntelliJ für Ihre Java-Entwicklung verwenden und es ausprobieren möchten, finden Sie es unter https://bitbucket.org/balpha/varsity .


Es wäre großartig, eine Tastenkombination zum Falten / Entfalten von Deklarationstypen im aktuellen Editor zu haben. Tolles Plugin.
Hotkey

2
@hotkey Dies verwendet die in IntelliJ integrierte Code-Faltung, sodass Sie alles mit Strg-Umschalt-NumPadPlus entfalten können. Wenn sich der Cursor in einer Zeile befindet, die eine gefaltete Variablendeklaration enthält, können Sie die Deklarationen in der aktuellen Methode mit Strg-NumPadPlus und Strg-NumPadMinus falten / entfalten. Das Falten aller Deklarationen ist etwas umständlich. Sie haben alles gefaltet (Strg-Umschalt-NumPadMinus) und dann alles wieder entfaltet (Strg-Umschalt-NumPadPlus).
Balpha

18

Mit der Veröffentlichung von JDK 10 am 20. März enthält Java jetzt einen varreservierten Typnamen (kein Schlüsselwort - siehe unten), wie in JEP 286 angegeben . Für lokale Variablen gilt jetzt Folgendes in Java 10 oder höher:

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

Der varreservierte Typname in Java ist nahezu identisch mit dem varSchlüsselwort in C #, da beide eine implizite Typisierung ermöglichen (wichtige Unterschiede siehe unten). varin Java kann nur für implizite Typinferenz in den folgenden Kontexten verwendet werden (wie in JEP 286 aufgezählt : Ziele ):

  • lokale Variablen mit Initialisierern
  • Indizes in der erweiterten for-Schleife
  • Einheimische in einer traditionellen for-Schleife deklariert

Daher var kann nicht für Felder, Rückgabetypen, Klassennamen oder Schnittstellennamen verwendet werden. Das Grundprinzip besteht darin, die Notwendigkeit zu beseitigen, lange Typnamen in die Deklaration und Definition lokaler Variablen aufzunehmen, wie in JEP 286 (verfasst von Brian Goetz) angegeben:

Wir möchten die Entwicklererfahrung verbessern, indem wir die mit dem Schreiben von Java-Code verbundene Zeremonie reduzieren und gleichzeitig Javas Engagement für die Sicherheit statischer Typen beibehalten, indem wir Entwicklern ermöglichen, die häufig unnötige Manifestdeklaration lokaler Variablentypen zu umgehen.

var Scoping in Java

Es ist zu beachten, dass dies varin Java kein Schlüsselwort ist, sondern ein reservierter Typname. Wie aus JEP 286 zitiert:

Der Bezeichner var ist kein Schlüsselwort. Stattdessen ist es ein reservierter Typname. Dies bedeutet, dass Code, der var als Variablen-, Methoden- oder Paketnamen verwendet, nicht betroffen ist. Code, der var als Klassen- oder Schnittstellennamen verwendet, ist betroffen (diese Namen sind jedoch in der Praxis selten, da sie gegen die üblichen Namenskonventionen verstoßen).

Da vares sich um einen reservierten Typnamen und kein Schlüsselwort handelt, kann er weiterhin für Paketnamen, Methodennamen und Variablennamen verwendet werden (zusammen mit seiner neuen Typinterferenzrolle). Im Folgenden finden Sie beispielsweise alle Beispiele für gültige Verwendungen varin Java:

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

Wie aus JEP 286 zitiert:

Diese Behandlung würde auf lokale Variablen mit Initialisierern, Indizes in der erweiterten for-Schleife und in einer traditionellen for-Schleife deklarierten Einheimischen beschränkt sein. Es ist nicht verfügbar für Methodenformale, Konstruktorformale, Methodenrückgabetypen, Felder, Catch-Formale oder andere Arten von Variablendeklarationen.

Unterschiede zwischen varin Java & C.

Dies ist ein bemerkenswerter Unterschied zwischen varC # und Java: varKann als Typname in C # verwendet werden, kann jedoch nicht als Klassenname oder Schnittstellenname in Java verwendet werden. Gemäß der C # -Dokumentation (implizit typisierte lokale Variablen) :

Wenn sich ein Typ mit dem Namen varim Gültigkeitsbereich befindet, wird das varSchlüsselwort in diesen Typnamen aufgelöst und nicht als Teil einer implizit typisierten lokalen Variablendeklaration behandelt.

Die Möglichkeit, varin C # als Typname zu verwenden, führt zu einer gewissen Komplexität und führt einige komplizierte Auflösungsregeln ein, die varin Java vermieden werden, indem sie varals Klassen- oder Schnittstellenname nicht zugelassen werden. Informationen zur Komplexität von varTypnamen in C # finden Sie unter Einschränkungen für implizit typisierte Variablendeklarationen . Weitere Informationen zu den Gründen für die Scoping-Entscheidung für var in Java finden Sie in JEP 286: Scoping Choices .


Gibt es einen Unterschied zwischen Java und c #, den Sie nicht varfür Felder oder Rückgabetypen verwenden können? Warum ist es wichtig zu beachten?
user1306322

@ user1306322 In diesem Zusammenhang Nr. varin Java kann nicht für Felder oder Rückgabetypen verwendet werden. Dies ist wichtig, da diese Einschränkung varkontextsensitiv ist und nur in einigen Kontexten (lokalen Variablen) und nicht in anderen verwendet werden kann. Dies ist nicht unbedingt ein Unterschied zwischen Java und C #, der beachtet werden sollte, sondern eine wichtige Einschränkung im Allgemeinen bei der Verwendung varin Java.
Justin Albano

Ich habe gerade nachgeschlagen und es scheint, als könnten Sie in c # vareinen Klassennamen erstellen und als solchen verwenden. Technisch gesehen ist es im Fall von c # ein "Kontextschlüsselwort", aber in Java scheint es, dass Sie nicht dasselbe tun können. Korrigiere mich, wenn ich falsch liege.
user1306322

1
Du hast Recht. Sie können varin Java keinen Klassennamen oder Schnittstellennamen verwenden (was ohnehin nicht üblich ist), aber Sie können ihn für Variablennamen, Methodennamen und Paketnamen verwenden. Beispiel: var var = 1;Ist eine gültige Java-Anweisung, aber der Versuch, eine Klasse zu deklarieren, public class var {}führt zu einem Fehler : as of release 10, 'var' is a restricted local variable type and cannot be used for type declarations. Ich habe die Antwort oben aktualisiert, um detaillierter auf die Gründe für varJava und die Unterschiede zu varC # einzugehen.
Justin Albano

11

Es wird in JDK 10 unterstützt. Es ist sogar möglich, es im Early Access Build in Aktion zu sehen .

Der JEP 286 :

Erweitern Sie die Java-Sprache, um die Typinferenz auf Deklarationen lokaler Variablen mit Initialisierern zu erweitern.

Also jetzt anstatt zu schreiben:

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

Du schreibst:

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

Anmerkungen:

  • varist jetzt ein reservierter Typname
  • Java setzt sich weiterhin für statische Typisierung ein!
  • Es kann nur in lokalen Variablendeklarationen verwendet werden

Wenn Sie es ausprobieren möchten, ohne Java auf Ihrem lokalen System zu installieren, habe ich ein Docker-Image mit JDK 10 erstellt:

$ 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
Beachten Sie, dass der von Ihnen angegebene Code (vorher / nachher var) nicht gleichwertig ist. Im varBeispiel listist vom Typ ArrayList, nicht a List.
Gili

8

Eine einfache Lösung (vorausgesetzt, Sie verwenden eine anständige IDE) besteht darin, überall "int" einzugeben und dann den Typ für Sie festzulegen.

Ich habe gerade eine Klasse namens 'var' hinzugefügt, damit ich nichts anderes eingeben muss.

Der Code ist immer noch zu ausführlich, aber zumindest müssen Sie ihn nicht eingeben!


Wenn Sie "anständige IDE" sagen, ist Eclipse * ausgeschlossen? - Das scheint in Luna nicht zu funktionieren (zumindest als ich es gerade ausprobiert habe int) - Vermisse ich etwas? (*:
Obwohl

@ BrainSlugs83 Keine Ahnung, ich verwende IDEA, habe Eclipse vorher nicht wirklich verwendet. Korrigiert es nicht die Typen für Sie? Ich bin an c # / visual studio / resharper gewöhnt, was wie IDEA ist, außer dass es tatsächlich richtig funktioniert! In allen Jetbrains können Sie die Alt-Eingabetaste drücken, um eine Liste mit Vorschlägen zu erhalten, wenn ein Fehler auftritt. Wenn Sie also den Typ auf int setzen, wird ein Fehler angezeigt, den Sie bei Alt-Eingabe eingeben und zum Sortieren des Typs veranlassen können
JonnyRaa

5

Sie können Kotlin von JetBrains ansehen , aber es ist wertvoll. nicht var.


4
Kotlin hat val und var. val ist gleichbedeutend mit der Deklaration einer Variablen final in Java, var ermöglicht eine Neuzuweisung.
Samlewis

5

Java 10 hat eine Inferenz des lokalen Variablentyps erhalten, daher hat es jetzt eine, vardie der C # 1 ziemlich weit entspricht (soweit mir bekannt ist).

Es kann auch auf nicht denotierbare Typen schließen (Typen, die vom Programmierer an dieser Stelle nicht benannt werden konnten; wobei die nicht denotierbaren Typen unterschiedlich sind). Siehe z. B. Tricks mit varund anonyme Klassen (die Sie niemals bei der Arbeit verwenden sollten) .

Der einzige Unterschied, den ich finden konnte, ist der in C #,

Wenn sich ein Typ mit dem Namen var im Gültigkeitsbereich befindet, wird das Schlüsselwort var in diesen Typnamen aufgelöst und nicht als Teil einer implizit typisierten lokalen Variablendeklaration behandelt.

In Java 10 varist kein legaler Typname.


@Lii Ja, ich erinnere mich nicht, was ich hier gemeint habe, entfernt.
Alexey Romanov

Großartig! Entfernt meinen Kommentar, um den Verlauf zu bereinigen!
Lii

4

Ab Java 10, ist das Äquivalent ... var.


Gibt es irgendwelche Unterschiede? Ich meine, Sie wissen besser, als kurze Antworten wie diese zu schreiben, was mit Ihrem Wiederholungslevel alles zu tun hat. Und sicherlich muss es einige Unterschiede geben.
user1306322

@ user1306322 Das ist eine ganz andere Frage! Sie können das Java-10-Tag überprüfen, da viele Aspekte davon bereits abgefragt wurden.
Brian Goetz

Nun, dies ist die Frage, die Sie sich stellen sollten, wenn Sie dies googeln, da sie an erster Stelle steht und in jedem verwandten Beitrag in der Seitenleiste verlinkt ist. Ich nehme an, wenn Sie diese separate Frage kennen, die sie beantwortet, können Sie möglicherweise zumindest einen Link dazu erstellen oder Teile davon in Ihre Antwort aufnehmen.
user1306322

3

Ich weiß, dass dies älter ist, aber warum nicht eine var-Klasse erstellen und Konstruktoren mit unterschiedlichen Typen erstellen. Je nachdem, welche Konstruktoren aufgerufen werden, erhalten Sie var mit unterschiedlichen Typen. Sie können sogar Methoden einbauen, um einen Typ in einen anderen zu konvertieren.


3

Lombokunterstützt var, ist aber immer noch als experimentell klassifiziert:

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

Hier ist eine Gefahr, die Sie vermeiden sollten, wenn Sie versuchen, sie zu verwenden IntelliJ IDEA. Es scheint jedoch wie erwartet zu funktionieren, einschließlich der automatischen Vervollständigung und allem. Bis es eine "nicht hackige" Lösung gibt (z. B. aufgrund von JEP 286: Typinferenz lokaler Variablen ), ist dies möglicherweise die beste Wahl.

Beachten Sie, dass dies auch von valunterstützt wird, Lombokohne ein zu ändern oder zu erstellen lombok.config.


2

Sie können in Java 10, aber nur für Local Variablen, dh

Sie können,

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

Aber kann nicht,

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

Weitere Informationen finden Sie in der Spezifikation .


2
Das ist falsch. varkann für viele Formen von nicht denotierbaren Typen verwendet werden, einschließlich Erfassungstypen, Schnittpunkttypen und anonymen Klassentypen. Ab Java 11 kann es auch auf Lambda-Parameter angewendet werden.
Brian Goetz

0

Im Allgemeinen können Sie die Objektklasse für jeden Typ verwenden, aber Sie müssen später Typumwandlung durchführen!

z.B:-

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, bitte überprüfen Sie alle anderen Antworten. Viele von ihnen haben -1 und das wahrscheinlich aus gutem Grund. Posten Sie nicht einfach irgendetwas, wenn Sie nicht sicher sind, ob es korrekt ist.
user1306322

@ user1306322 was ist das Problem in meiner Antwort! Kannst du das näher erläutern? Können wir die Objektklasse nicht für alle Datentypen verwenden?
Aditya Kumar

Objekt Objekt = 12; Objekt object1 = "Aditya"; Objekt 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

Das Problem ist, dass Sie die Frage nicht verstanden haben. Die Frage war nicht "wie man diese Arbeit macht", sondern "gibt es so etwas". Sie beantworten die falsche Frage. Mit dem varWort, das jetzt offiziell in der Sprache ist, bezieht sich Ihre Antwort auch auf den jetzt altmodischen Weg.
user1306322

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.