[JAVA] [JDK 10] Typinferenz mit var

Dieser Artikel ist der 16. Tag von Java Adventskalender 2017.

Betrachten wir den Inhalt und die Verwendung von JEP 286: Typinferenz lokaler Variablen, die in JDK 10 hinzugefügt werden.

(Hinzugefügt am 22.03.2018) Informationen zur Funktionsprüfung mit der offiziellen JDK10-Version

Die offizielle Version von JDK10 wurde am 20. März 2018 veröffentlicht, daher habe ich überprüft, ob sich seit dem Schreiben dieses Artikels Änderungen ergeben haben.

C:\Users\chooyan>"C:\Program Files\java\jdk-10\bin\javac.exe" -version
javac 10

Soweit ich den Vorgang überprüft und die folgende Seite angesehen habe, schien sich der in diesem Artikel beschriebene Inhalt nicht zu ändern.

Java 10 Local Variable Type Inference | Oracle Developers

Abgesehen davon erwähnt der obige Artikel auch das Verhalten beim Schreiben von "var list = new ArrayList <> ();", worüber im Kommentarbereich dieses Artikels gesprochen wurde.

Zusammenfassend wird es als "ArrayList " behandelt, und es gibt keinen besonderen Vorteil. Vermeiden Sie es daher.

(Ergänzung bisher)

Zielgruppe dieses Artikels

Dieser Beitrag

Dieser Artikel ist für diejenigen gedacht, die sagen.

Da var ein Schlüsselwort ist, das häufig in anderen Sprachen als Java vorkommt, können einige Leute erwarten, es zu vergleichen, aber ich habe nicht das Wissen und die Erfahrung, um darüber zu schreiben, daher dieser Artikel Dann ist der Inhalt wie die Einführung der neu eingeführten "var", die sich nur auf Java konzentriert.

Ich habe es so geschrieben, dass es der beste Artikel für diejenigen ist, die sich grob auf Javas var vorbereiten möchten, also hoffe ich, dass Sie darauf basierend weiterlesen werden.

JDK zu verwenden

Dieser Artikel verwendet JDK 10 Early-Access-Builds.

Durch Herunterladen und Installieren des JDK und Verwenden von "javac" und "jshell" im Ordner "bin" können Sie den Quellcode mit "var" wie der Beispielquelle in diesem Artikel testen.

C:\Users\chooyan>"C:\Program Files\java\jdk-10\bin\javac.exe" -version
javac 10-ea

Übersicht über var

In JEP 286: Typinferenz lokaler Variablen wird die Verwendung von "var" verwendet, um den Typ beim Deklarieren einer Variablen anzugeben. Lassen Sie uns den Code für vereinfachen.

Bevor wir darauf eingehen, werfen wir einen Blick auf den Beispielcode. In diesem Artikel verwenden wir "jshell" für Beispielcode, der in wenigen Zeilen vervollständigt werden kann.

Das folgende Beispiel zeigt das Deklarieren einer Variablen vom Typ int.

jshell


jshell> int limit = 20; //Deklarieren Sie eine Variable vom Typ int auf herkömmliche Weise
limit ==> 20

jshell> var limit = 20; //Deklarieren Sie eine Variable vom Typ int mit var
limit ==> 20

Die Typdeklaration für "int" wurde durch "var" ersetzt.

Gleiches gilt für Objekttypen. Schauen wir uns einige an.

jshell


jshell> String name = "chooyan_eng"; //Deklarieren Sie eine Variable vom Typ String auf herkömmliche Weise
name ==> "chooyan_eng"

jshell> var name = "chooyan_eng"; //Deklarieren Sie eine Variable vom Typ String mit var
name ==> "chooyan_eng"

jshell> List<String> idList = new ArrayList<>(); //Liste auf traditionelle Weise<String>Deklarieren Sie eine Variable vom Typ
idList ==> []

jshell> var idList = new ArrayList<String>(); //Liste mit var<String>Deklarieren Sie eine Variable vom Typ
idList ==> []

Wenn die rechte Seite eine Methode ist, können Sie auch "var" verwenden, da der Rückgabetyp aus dieser Signatur hervorgeht.

jshell


jshell> private int sum(int x, int y) {
   ...>     return x + y;
   ...> }

|Erstellt das Folgende:Methodensumme(int,int)

jshell> var s = sum(4, 5);

s ==> 9

Was denken Sie. Wie oben erwähnt, besteht die in JEP286 berücksichtigte neue Typinferenz von Java darin, den Schreibaufwand zu verringern und das Lesen des Codes zu erleichtern, indem die Typspezifikation auf der linken Seite durch "var" ersetzt wird.

var limit

Nun, ich habe geschrieben, dass Sie die Typspezifikation auf der linken Seite mit dem neuen "var" vereinfachen können, aber es ist nicht immer möglich, "var" zu verwenden.

Um var verwenden zu können, müssen die folgenden Bedingungen erfüllt sein.

Als Voraussetzung ist Javas var " Da der Typ der linken Seite zur Kompilierungszeit durch Betrachten der rechten Seite bestimmt werden kann, kann die Typspezifikation der linken Seite zum Zeitpunkt der Codierung weggelassen werden ". Es ist kein Mechanismus, der "den Typ zur Laufzeit bestimmt".

Um es etwas detaillierter zu erklären, zum Beispiel, wenn Sie eine Instanz der Klasse "Artikel" erstellen und sie bis jetzt der Variablen "Artikel" zuweisen

jshell


jshell> Article article = new Article();

article ==> Article@59494225

Ich schrieb. Wenn Sie genau hinschauen, muss der Typ der Variablen für die Zuweisung vom Typ "Artikel" (oder der übergeordneten Klasse) sein, solange die auf der rechten Seite erstellte Instanz vom Typ "Artikel" ist. Und es liegt immer noch am Compiler, einen Fehler zu machen, wenn dies nicht der Fall ist.

Wenn Sie dann nur "var" auf der linken Seite schreiben und dem Compiler erlauben, auf den tatsächlichen Variablentyp zu schließen, ist dies praktisch, da Sie nicht dieselbe Klasse zweimal in eine Zeile schreiben müssen. Ist die Idee von Javas var.

Umgekehrt kann var nicht in Situationen verwendet werden, in denen der Typ nicht eindeutig bestimmt wird, indem zur Kompilierungszeit auf die rechte Seite geschaut wird. Von hier aus werde ich in der Reihenfolge erklären, in welcher Art von Fall "der Typ nicht klar bestimmt ist, selbst wenn Sie auf die rechte Seite schauen".

Wenn der Typ nicht einfach durch einen Blick auf die rechte Seite bestimmt werden kann

In einigen Fällen kann der Typ nicht allein durch einen Blick auf die rechte Seite bestimmt werden.

Die rechte Seite ist null

Ich denke, es ist nicht ungewöhnlich, beim Deklarieren einer Variablen "null" (oder nichts) zuzuweisen.

Zum Beispiel


private Article getArticle(int id) {
    Article article = null;

    if (isOnline()) {
        article = requestArticle(id);
    } else {
        article = selectArticleFromCache(id);
    }

    //Einige Verarbeitung für die Artikelvariable

    return article;
}

Wenn Sie die Zuweisungsmethode in der if-Anweisung ändern möchten, aber auf die Variable außerhalb der if-Anweisung zugreifen möchten, deklarieren Sie die Variable "article" vor der if-Anweisung und initialisieren Sie sie mit null. müssen es tun.

Aber zu diesem Zeitpunkt

Article article = null;

Variable Aussage

var article = null;

Kann nicht geschrieben werden. Dies liegt daran, dass die rechte Seite dieser Zeile null ist, sodass der Compiler nicht bestimmen kann, welcher Typ der Variablen article zugewiesen ist.

Wenn ich es tatsächlich mit jshell versuche,

jshell


jshell> var article = null;

|Error:
|  cannot infer type for local variable article
|    (variable initializer is 'null')
|  var article = null;
|  ^--------------^

Ich erhalte die Fehlermeldung, dass eine Typinferenz mit null nicht möglich ist.

Kann nicht mit Lambda-Typ verwendet werden

In einer Situation, in der var nicht verwendet werden kann, gibt es einen Fall, in dem der Typ auf der rechten Seite durch den Lambda-Ausdruck weggelassen wird.

Wenn Sie beispielsweise eine anonyme Klasse erstellen möchten, die die Klasse "Runnable" wie unten gezeigt erbt, können Sie in der aktuellen Java-Version einen Lambda-Ausdruck verwenden und wie folgt schreiben.

jshell


jshell> Runnable runner = () -> { System.out.println("run!"); };

runner ==> $Lambda$15/1471868639@343f4d3d

Wenn ich dagegen versuche, dies mit dem neuen var zu schreiben, sieht es so aus:

jshell


jshell> var runner = () -> { System.out.println("run!"); };

|Error:
|  cannot infer type for local variable runner
|    (lambda expression needs an explicit target-type)
|  var runner = () -> { System.out.println("run!"); };
|  ^--------------------------------------------^

Da der Lambda-Ausdruck auf der rechten Seite keine explizite Typspezifikation enthält, wird die Meldung angezeigt, dass "var" auf der linken Seite den Typ nicht bestimmen kann. Mit anderen Worten, Typauslassung durch Lambda-Ausdruck und var können nicht gleichzeitig verwendet werden.

In einem solchen Fall können Sie den Fehler übrigens vermeiden, indem Sie den Typ wie folgt explizit konvertieren.

jshell


jshell> var runner = (Runnable) (() -> {System.out.println("run!");})
runner ==> $Lambda$15/87765719@5442a311

In diesem Fall ist es jedoch einfacher, den Code zu lesen, indem Sie den Typ auf der linken Seite angeben, ohne var zu verwenden, sodass Sie ihn nicht so schreiben müssen.

jshell


jshell> Runnable runner = () -> {System.out.println("run!");};
runner ==> $Lambda$15/87765719@5442a311

Kann nicht mit Instanzvariablen verwendet werden

Wie bereits erwähnt, kann "var" nur für "lokale Variablen" verwendet werden. Mit anderen Worten, wenn Sie versuchen, es für eine Instanzvariable wie unten gezeigt zu verwenden, tritt ein Fehler auf.

jshell


jshell> class Article {
   ...>     var id = 0;
   ...>     var title = "";
   ...> }

|Error:
|  'var' is not allowed here
|      var id = 0;
|      ^-^
|Error:
|  'var' is not allowed here
|      var title = "";
|      ^-^

Die Fehlermeldung bleibt gleich. Es wird gesagt, dass "es hier nicht verwendet werden kann".

Ich kenne die Details nicht, aber bedeutet dies, dass nur lokale Variablen eingeschränkt sind, da es schwierig wird zu beurteilen, ob der Anwendungsbereich groß wird? Dieser Bereich wurde nicht untersucht (sorry), aber es scheint so etwas zu sein.

Kann nicht zum Initialisieren eines Arrays ohne Typdeklaration verwendet werden

Sie können var nicht verwenden, wenn Sie ein Array ohne die Typdeklaration erstellen, wie unten gezeigt.

jshell


jshell> var arr = {1, 2, 3}

|Error:
|  cannot infer type for local variable arr
|    (array initializer needs an explicit target-type)
|  var arr = {1, 2, 3};
|  ^------------------^

Wenn Sie dagegen den Typ mit "new int []" angeben, gibt es kein Problem.

jshell



jshell> var arr = new int[]{1, 2, 3}
arr ==> int[3] { 1, 2, 3 }

Es ist weniger wahrscheinlich, dass "var" als Typmenge verwendet wird, aber hier ist es besser, mit "var" zu deklarieren, nachdem der Typ wie der letztere angegeben wurde, um mit anderen Deklarationsmethoden konsistent zu sein. Ich fühlte mich wie.

FAQ mit der Einführung von var

Darüber hinaus möchte ich darüber nachdenken, was mit der Einführung von "var" in einem Frage-und-Antwort-Format fraglich erscheint.

Frage 1: Was ist, wenn ich es "endgültig" machen möchte?

Im Fall von Kotlin sind beispielsweise die Variablen, die neu zugewiesen werden können, "var", und die Variablen, die nicht neu zugewiesen werden können, sind "val".

Java hat derzeit nichts, was eine solche "nicht neu zuweisbare" Var "darstellt. Stellen Sie einfach "final" wie zuvor vor die Form.

VarSample.java


public class VarSample {
    public static void main(String[] args) {
        final var id = 2;
        id = 3;
        System.out.println(id);
    }
}

Wenn Sie den obigen Code kompilieren, sehen Sie, dass es nicht mehr möglich ist, Variablen mit final zuzuweisen.

$ javac VarSample.java

VarSample.java:4:Error:Sie können der endgültigen Variablen-ID keinen Wert zuweisen
        id = 3;
        ^

Dann stellt sich die Frage, ob die Konstante als "public static final var" geschrieben werden soll. Dies hat jedoch die Einschränkung, dass "var" nur für lokale Variablen verwendet werden kann, sodass die Konstante dieselbe bleibt wie zuvor.


public static final String DEFAULT_ID = "9999";

Es wird beschrieben als.

Das einzige Qualifikationsmerkmal, das an eine lokale Variable angehängt werden kann, ist "final", sodass Sie wahrscheinlich nicht über die Kompromisse mit anderen Qualifikationsmerkmalen nachdenken werden.

F2. Ich möchte es an der Schnittstelle empfangen

var erhält die rechte Seite mit dem von der rechten Seite abgeleiteten Typ.

Mit anderen Worten, es ist nicht möglich, die generierte konkrete Klasse in der Schnittstelle zu empfangen, die bisher wie ein Klischee geschrieben wurde.

jshell


//Generierte ArrayList<String>Eine Instanz von List, die eine Schnittstelle ist<String>Empfangen bei
jshell> List<String> idList = new ArrayList<>();  

jshell


//Sie können den Typ nicht angeben, der bei Verwendung von var empfangen werden soll
jshell> var idList = new ArrayList<String>();  

Wenn Sie sich angewöhnen, "so viel wie möglich mit Objekten in der Benutzeroberfläche umzugehen!", Scheint dies für einen Moment eine sehr schwierige Änderung zu sein, aber in Wirklichkeit ist dies selten unpraktisch.

Wenn es von einer konkreten Klasse empfangen wird, führt dies sicherlich zu Unannehmlichkeiten beim Zuweisen einer anderen Klasse mit derselben Schnittstelle wie unten gezeigt.

jshell


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

jshell> idList = new LinkedList<String>();

|Error:
|Inkompatibler Typ: java.util.LinkedList<java.lang.String>Nach Java.util.ArrayList<java.lang.String>Kann nicht konvertiert werden:
|  idList = new LinkedList<String>();
|           ^----------------------^

Sie sollten jedoch selten solchen Code schreiben.

Erstens wird es in der Schnittstelle so behandelt, dass jede konkrete Klasse wie ein Methodenargument oder ein Rückgabewert behandelt werden kann (die konkrete Klasse kann nach Bedarf umgeschaltet werden).

Und eine solche Verwendung ist mit var weiterhin möglich.

jshell


jshell> private List<String> getIdList() {
   ...>     if (isArrayListSuitable()) {
   ...>         return new ArrayList<String>();
   ...>     } else if (isLinkedListSuitable()) {
   ...>         return new LinkedList<String>();
   ...>     }
   ...>     return new ArrayList<String>();
   ...> }
|Erstellt das Folgende:Methode getIdList()

jshell> var idList = getIdList();
idList ==> []

Obwohl var automatisch von der konkreten Klasse empfangen wird, hat es nur begrenzte Auswirkungen, es sei denn, es ist nur verfügbar, wenn eine lokale Variable deklariert wird.

F3. Ich habe bereits eine Klasse mit dem Namen "var" erstellt.

Das ist ein Problem. Das Problem ist, dass ich einen Klassennamen namens "var" erstellt habe, der von der Java-Namenskonvention abweicht.

Selbst in JEP286 besteht eines der Risiken bei der Einführung von "var" in dem Kompatibilitätsproblem, wenn die Klasse "var" bereits definiert ist.

Risk: source incompatibilities (someone may have used var as a type name.)

Erstens ist es jedoch unwahrscheinlich, dass Sie ein Wort verwenden, das mit einem Kleinbuchstaben als Klassennamen beginnt, oder sogar das Wort "var", das in anderen Sprachen häufig als Schlüsselwort als Typname verwendet wird, also die Anweisung, "var" zu einem neuen reservierten Wort zu machen Es steht geschrieben, dass sich nichts ändert.

Mitigated with reserved type names; names like var do not conform to the naming conventions for types, and therefore are unlikely to be used as types. The name var is commonly used as an identifier; we continue to allow this.

Wenn Sie bereits eine Klasse mit dem Namen "var" erstellt haben, müssen Sie diese vor der Migration auf JDK 10 umbenennen.

Es gibt kein besonderes Problem mit dem Variablennamen "var". Es ist etwas schwer zu lesen, kann aber in Verbindung mit dem Schlüsselwort "var" verwendet werden.

jshell


jshell> int var = 1; //Definieren Sie die Variable vom Typ int var
var ==> 1

jshell> var = 2; //Weisen Sie der Variablen var einen anderen Wert zu
var ==> 2

jshell> var var = 1; //Definieren Sie die Variable var mit var (der Typ int wird abgeleitet)
var ==> 1

Zusammenfassung

Wie oben erwähnt, habe ich die "var", die in JDK 10 eingeführt wird, mit der aktuell veröffentlichten Early-Access-Version von JDK 10 überprüft.

Wenn Sie Sprachen wie JavaScript verwenden und "var" hören, haben Sie möglicherweise den Eindruck, dass Java zu einer Sprache wird, deren Typ sich dynamisch ändert, aber "var" von Java ist "linke Seite". Ich denke, es wurde verstanden, dass sich das Verhalten nicht besonders ändert, weil es um "die Typspezifikation von" geht, die weggelassen werden kann.

Wenn var verfügbar wird, wird erwartet, dass unterschiedliche Kodierungsstandards und -gewohnheiten entstehen, daher denke ich, dass es von nun an reibungslos akzeptiert werden kann, wenn man es sich vorstellt. Überlegen. Bitte lassen Sie die Early-Access-Version von JDK10 fallen und probieren Sie es aus.

Außerdem habe ich den in JEP 286 beschriebenen Inhalt noch nicht gelesen und verstanden, sodass möglicherweise einige Fehler im Inhalt vorliegen. nicht. Wenn Sie irgendwelche seltsamen Punkte haben, kommentieren Sie bitte.


Werbung

Neulich schrieb ich einen Artikel Ich habe ein Repository "Code Your Ruby" für Leute erstellt, die in Ruby arbeiten möchten.

__ "Ich bin jetzt Java-Ingenieur, möchte aber von nun an an Ruby arbeiten" __ Ein Repository namens Code Your Ruby, das sich ideal zum Lernen eignet Wir haben es eingeführt. Wenn Sie also denken, dass Sie es sind, lesen Sie es bitte.

Recommended Posts

[JDK 10] Typinferenz mit var
[Java Siler] Informationen zur Typinferenz von var