Quel est l'équivalent du mot clé C # 'var' en Java?

264

Une utilisation du mot clé var en C # est la déclaration de type implicite. Quelle est la syntaxe équivalente Java pour var ?

Arturo
la source
4
val(ou var) si vous utilisez un langage "de remplacement Java" particulier ;-)
6
@pst: ce serait Scala? Hm oui, ça l'est.
rsenna
Pour IntelliJ, j'ai soumis cela comme une demande de fonctionnalité: youtrack.jetbrains.com/issue/IDEA-102808 L'IDE peut réduire le code pour afficher val ou var même si le code sous-jacent ne l'aurait pas.
Jon Onstott
@Jon J'ai piraté quelque chose ensemble pour IntelliJ, voir ma réponse .
balpha
3
Il y a maintenant une proposition pour que cette fonctionnalité soit incluse dans Java - openjdk.java.net/jeps/286
McGin

Réponses:

248

Il n'y en a pas. Hélas, vous devez taper le nom complet du type.

Edit: 7 ans après avoir été publié, l'inférence de type pour les variables locales (avec var) a été ajoutée dans Java 10.

Edit: 6 ans après avoir été posté, pour recueillir certains des commentaires ci-dessous:

  • La raison pour laquelle C # a le varmot-clé est qu'il est possible d'avoir des types sans nom dans .NET. Par exemple:

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

    Dans ce cas, il serait impossible de donner un type approprié à myData. Il y a 6 ans, cela était impossible en Java (tous les types avaient des noms, même s'ils étaient extrêmement bavards et peu bavards). Je ne sais pas si cela a changé entre-temps.

  • varn'est pas le même que dynamic. varLes variables sont toujours 100% typées statiquement. Cela ne compilera pas:

    var myString = "foo";
    myString = 3;
  • varest également utile lorsque le type est évident dans le contexte. Par exemple:

    var currentUser = User.GetCurrent();

    Je peux dire que dans n'importe quel code dont je suis responsable, il currentUsercontient une Userclasse ou une classe dérivée. Évidemment, si votre implémentation de User.GetCurrentreturn retourne un int, alors c'est peut-être un inconvénient pour vous.

  • Cela n'a rien à voir avec var, mais si vous avez d'étranges hiérarchies d'héritage où vous masquez des méthodes avec d'autres méthodes (par exemple new public void DoAThing()), n'oubliez pas que les méthodes non virtuelles sont affectées par le type sous lequel elles sont converties.

    Je ne peux pas imaginer un scénario du monde réel où cela indique une bonne conception, mais cela peut ne pas fonctionner comme prévu:

    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

    Comme indiqué, les méthodes virtuelles ne sont pas affectées par cela.

  • Non, il n'y a aucun moyen non maladroit d'initialiser un varsans variable réelle.

    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

    Dans ce cas, faites-le à l'ancienne:

    object foo6;
Mike Caron
la source
11
@Mike Caron: C # a [par défaut] des appels non virtuels et les opérateurs ne sont pas virtuels donc ... var p = new X(); p.Z()n'est pas le même que SuperX p = new X(); p.Z()pour tous les X et et SuperX, même si X : SuperX. Avec varle type statique de pest toujours Xdans le premier exemple ci-dessus, mais toujours SuperXdans le deuxième exemple. Une différence subtile mais importante à prendre en compte. Mais votre réponse est très correcte :-)
200
@ Jon Hanna: varne rend pas le code moins clair. Plutôt le contraire à mon avis. Pourquoi par exemple écrire le type deux (ou même trois) fois sur la même ligne lorsque vous le déclarez et l'instanciez ( RadioButton radioButton = new RadioButton();)? varvous fait plutôt réfléchir à deux fois lorsque vous nommez vos variables car cela met l'accent sur la fonctionnalité plutôt que sur le type (par exemple, UserCollection collection = new userRepository.GetUsers();se transforme plus naturellement en var users = userRepository.GetUsers();). Si vous pensez que ce varn'est pas clair, c'est simplement parce que vous n'y êtes pas habitué.
Martin Odhelius
4
@MartinOdhelius varpeut très certainement rendre le code clair bien utilisé, mais il peut aussi le rendre mal utilisé trop mal; comme de nombreuses options de formatage. L'équilibre varie en fonction de l'utilisation que vous faites des objets anonymes et des génériques, qui n'existaient ni dans .NET 1.0, ce qui le rend moins utile comme mot clé hypothétique dans la première version de C♯. Je ne nommerais un RadioButton radioButtondans le cas d'une méthode d'usine ou d'aide où la seule chose importante sur le bouton était qu'il s'agissait d'un RadioButton, sinon c'est de la folie avec ou sans var.
Jon Hanna
6
@ Jon Hanna: J'étais autrefois aussi critique varque vous, sinon plus, mais j'ai changé d'avis, et c'est peut-être aussi simple qu'une question d'opinions différentes, parce que je pense toujours que vous vous trompez quand vous dites que c'est un peu importe combien vous utilisez des objets anonymes et génériques;) La déclaration de type est le plus souvent juste du bruit de code, si vous ne pouvez pas comprendre le code sans lui, le code n'est probablement pas clair dans les deux cas.
Martin Odhelius
3
Vous confondez var avec des types anonymes . varlui-même demande simplement au compilateur de déduire le type de l'affectation; c'est du sucre syntaxique. J'en étais sceptique au début, mais je l'utilise religieusement et je n'ai pas encore rencontré un moment où cela a causé de la confusion. Il supprime la redondance lors de l'instanciation et supprime la nécessité de vérifier le type lors du référencement. Il n'y a pas d'équivalent JAVA en date de JAVA 9.
Robear
46

Si vous ajoutez Lombok à votre projet, vous pouvez utiliser son mot-clé val .

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

darthtrevino
la source
1
@rightfold: les objets dont la référence est finalne sont pas nécessairement immuables. Considérezfinal StringBuilder strB = new StringBuilder("My reference is final"); strB.append("I'm not immutable");
Matthias Braun
1
Depuis lombok v1.16.12, il existe également un support expérimental pour var. projectlombok.org/features/experimental/var.html
Roel Spilker
@MatthiasBraun, votre exemple est faux. Dans ce cas, la classe StringBuilder elle-même est immuable, vous ajoutez simplement une valeur de chaîne à sa structure interne à l'aide de la méthode, c'est totalement légal.
Andzej Maciusovic
27

JEP - Proposition d'amélioration du JDK

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

JEP 286: Inférence de type variable locale

Auteur Brian Goetz

// Goals:
var list = new ArrayList<String>();  // infers ArrayList<String>
var stream = list.stream();          // infers Stream<String>
myrtille0xff
la source
Quelle version de Java? dix?
Peter Mortensen
@PeterMortensen Oui. JEP 286 a été accepté et publié dans JDK 10 (voir 286 sous Fonctionnalités sur openjdk.java.net/projects/jdk/10 ).
Justin Albano
20

J'ai concocté un plugin pour IntelliJ qui - en quelque sorte - vous donne varen Java. C'est un hack, donc les clauses de non-responsabilité habituelles s'appliquent, mais si vous utilisez IntelliJ pour votre développement Java et que vous voulez l'essayer, c'est sur https://bitbucket.org/balpha/varsity .

balpha
la source
Ce serait formidable d'avoir un raccourci clavier pour plier / déplier les types de déclaration dans l'éditeur actuel. Excellent plugin cependant.
raccourci clavier
2
@hotkey Ceci utilise le pliage de code intégré d'IntelliJ, vous pouvez donc tout déplier avec Ctrl-Shift-NumPadPlus. Lorsque le curseur se trouve sur une ligne contenant une déclaration de variable pliée, vous pouvez Ctrl-NumPadPlus et Ctrl-NumPadMinus pour plier / déplier les déclarations dans la méthode actuelle. Plier toutes les déclarations est un peu gênant, vous devez tout plier (Ctrl-Shift-NumPadMinus) puis tout déplier à nouveau (Ctrl-Shift-NumPadPlus).
balpha
18

Avec la sortie de JDK 10 le 20 mars, Java inclut désormais un varnom de type réservé (pas un mot-clé - voir ci-dessous) comme spécifié dans JEP 286 . Pour les variables locales, ce qui suit est maintenant valide dans Java 10 ou supérieur:

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

Le varnom de type réservé en Java est presque identique au varmot - clé en C # dans la mesure où les deux permettent une saisie implicite (voir ci-dessous pour les différences importantes). varen Java ne peut être utilisé pour l'inférence de type implicite que dans les contextes suivants (comme énuméré dans JEP 286: Objectifs ):

  • variables locales avec initialiseurs
  • index dans la boucle for améliorée
  • les habitants déclarés dans une boucle for traditionnelle

Par conséquent, var ne peut pas être utilisé pour les champs, les types de retour, les noms de classe ou les noms d'interface. Sa raison d'être est de supprimer la nécessité d'inclure des noms de type longs lors de la déclaration et de la définition de variables locales, comme indiqué dans JEP 286 (rédigé par Brian Goetz):

Nous cherchons à améliorer l'expérience des développeurs en réduisant la cérémonie associée à l'écriture de code Java, tout en maintenant l'engagement de Java envers la sécurité des types statiques, en permettant aux développeurs d'éluder la déclaration manifeste souvent inutile des types de variables locales.

var Portée en Java

Il convient de noter qu'il varne s'agit pas d'un mot clé en Java, mais plutôt d'un nom de type réservé. Comme cité dans JEP 286:

L'identifiant var n'est pas un mot-clé; il s'agit plutôt d'un nom de type réservé. Cela signifie que le code qui utilise var comme variable, méthode ou nom de package ne sera pas affecté; le code qui utilise var comme nom de classe ou d'interface sera affecté (mais ces noms sont rares dans la pratique, car ils violent les conventions de dénomination habituelles).

Notez que puisqu'il vars'agit d'un nom de type réservé et non d'un mot-clé, il peut toujours être utilisé pour les noms de package, les noms de méthode et les noms de variable (avec son nouveau rôle d'interférence de type). Par exemple, ce qui suit sont tous des exemples d'utilisations valides de varJava:

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

Comme cité dans JEP 286:

Ce traitement serait limité aux variables locales avec des initialiseurs, des index dans la boucle for améliorée et des sections locales déclarées dans une boucle for traditionnelle; il ne serait pas disponible pour les formals de méthode, les formals de constructeur, les types de retour de méthode, les champs, les formals catch ou tout autre type de déclaration de variable.

Différences entre varJava et C

Il s'agit d'une différence notable entre varC # et Java, notamment: varpeut être utilisé comme nom de type en C # mais ne peut pas être utilisé comme nom de classe ou nom d'interface en Java. Selon la documentation C # (Variables locales implicitement typées) :

Si un type nommé varest dans la portée, le varmot - clé se résoudra en ce nom de type et ne sera pas traité comme faisant partie d'une déclaration de variable locale implicitement typée.

La possibilité d'utiliser varcomme nom de type en C # crée une certaine complexité et introduit des règles de résolution complexes, qui sont évitées par varen Java en interdisant en vartant que nom de classe ou d'interface. Pour plus d'informations sur la complexité des varnoms de type en C #, consultez Restrictions s'appliquent aux déclarations de variable implicitement typées . Pour plus d'informations sur la justification de la décision de délimitation de `var en Java, voir JEP 286: Choix de délimitation .

Justin Albano
la source
Y a-t-il une différence entre Java et c # en ce que vous ne pouvez pas utiliser varpour les champs ou les types de retour? Pourquoi est-il important de le noter?
user1306322
@ user1306322 Dans ce contexte, non. varen Java ne peut pas être utilisé pour les champs ou les types de retour. Ceci est important car cette restriction rend le varcontexte sensible, où il ne peut être utilisé que dans certains contextes (variables locales) et pas dans d'autres. Ce n'est pas nécessairement une différence entre Java et C # qui doit être notée, mais une restriction importante en général lors de l'utilisation varen Java.
Justin Albano
Je viens de regarder et il semble qu'en c # vous pouvez faire varun nom de classe et l'utiliser comme tel. Techniquement, c'est un "mot-clé contextuel" en cas de c #, mais en Java il semble que vous ne puissiez pas faire de même. Corrige moi si je me trompe.
user1306322
1
Vous avez raison. Vous ne pouvez pas utiliser varcomme nom de classe ou nom d'interface en Java (ce qui n'est pas courant de toute façon), mais vous pouvez l'utiliser pour les noms de variable, les noms de méthode et les noms de package. Par exemple, var var = 1;est une instruction Java valide , mais en essayant de déclarer une classe comme public class var {}résultat une erreur: as of release 10, 'var' is a restricted local variable type and cannot be used for type declarations. J'ai mis à jour la réponse ci-dessus pour entrer plus en détail sur la raison d'être varde Java et ses différences avec varC #.
Justin Albano
11

Il sera pris en charge dans JDK 10. Il est même possible de le voir en action dans la version à accès anticipé .

Le JEP 286 :

Améliorez le langage Java pour étendre l'inférence de type aux déclarations de variables locales avec des initialiseurs.

Alors maintenant, au lieu d'écrire:

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

Vous écrivez:

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

Remarques:

  • varest maintenant un nom de type réservé
  • Java est toujours attaché à la frappe statique!
  • Il ne peut être utilisé que dans les déclarations de variables locales

Si vous voulez l'essayer sans installer Java sur votre système local, j'ai créé une image Docker avec JDK 10 installé dessus:

$ 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
la source
3
Attention, le code que vous avez fourni (avant / après var) n'est pas équivalent. Dans l' varexemple listest de type ArrayList, pas a List.
Gili
8

Une solution simple (en supposant que vous utilisez un IDE décent) consiste simplement à taper «int» partout, puis à le définir pour vous.

En fait, je viens d'ajouter une classe appelée «var», donc je n'ai pas à taper quelque chose de différent.

Le code est encore trop verbeux, mais au moins vous n'avez pas besoin de le taper!

JonnyRaa
la source
Lorsque vous dites "IDE décent", Eclipse * est-il exclu? - cela ne semble pas fonctionner dans Luna (du moins quand je viens de l'essayer avec int) - est-ce que je manque quelque chose? (*: alors que je n'appellerais jamais Eclipse un IDE décent, je ne peux pas juger pour les autres ...)
BrainSlugs83
@ BrainSlugs83 dunno J'utilise IDEA, pas vraiment utilisé éclipse avant. Cela ne vous convient-il pas? Je suis habitué à c # / visual studio / resharper qui est comme IDEA sauf qu'il fonctionne réellement correctement! Dans tous les jetbrains, vous pouvez appuyer sur alt-enter pour obtenir une liste de suggestions quand il y a une erreur - donc le réglage du type sur int introduit une erreur que vous pouvez alt-enter sur et le faire trier le type
JonnyRaa
5

Vous pouvez jeter un œil à Kotlin by JetBrains, mais c'est val. pas var.

Artiom
la source
4
Kotlin a val et var. val équivaut à déclarer une variable finale en java, var permet la réaffectation.
samlewis
5

Java 10 a obtenu une inférence de type de variable locale, alors maintenant il a varce qui est à peu près équivalent à celui de C # (pour autant que je sache).

Il peut également déduire des types non dénotables (types qui ne peuvent pas être nommés à cet endroit par le programmeur; bien que les types non dénotables soient différents). Voir par exemple les astuces avec varet les classes anonymes (que vous ne devriez jamais utiliser au travail) .

La seule différence que j'ai pu trouver est qu'en C #,

Si un type nommé var est dans la portée, le mot clé var se résoudra en ce nom de type et ne sera pas traité comme faisant partie d'une déclaration de variable locale implicitement typée.

En Java 10 varn'est pas un nom de type légal.

Alexey Romanov
la source
@Lii Oui, je ne me souviens pas de ce que je voulais dire ici, supprimé.
Alexey Romanov
Génial! Supprime mon commentaire pour nettoyer l'historique!
Lii
4

A partir de Java 10, l'équivalent est ... var.

Brian Goetz
la source
Y a-t-il des différences? Je veux dire que vous savez mieux que d'écrire de courtes réponses comme celle-ci, avec votre niveau de représentant n tous. Et il doit sûrement y avoir des différences.
user1306322
@ user1306322 C'est une question complètement distincte! Vous pouvez vérifier la balise java-10, car de nombreux aspects ont déjà été demandés.
Brian Goetz
Eh bien, c'est la question à regarder si vous cherchez sur Google, car cela vient en premier et est lié à tous les messages connexes dans la barre latérale. Donc, je suppose que si vous connaissez cette question distincte qui y répond, vous pourriez au moins y établir un lien ou en inclure des parties dans votre réponse.
user1306322
3

Je sais que c'est plus ancien mais pourquoi ne pas créer une classe var et créer des constructeurs avec différents types et en fonction des constructeurs invoqués, vous obtenez var avec un type différent. Vous pouvez même intégrer des méthodes pour convertir un type en un autre.

Sebastian Zaba
la source
3

Lombokprend en charge var mais il est toujours classé comme expérimental:

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

Voici un piège à éviter lorsque vous essayez de l'utiliser dans IntelliJ IDEA. Il semble fonctionner comme prévu, y compris l'achèvement automatique et tout. Jusqu'à ce qu'il existe une solution "non hacky" (par exemple en raison de JEP 286: Inférence de type variable locale ), cela pourrait être votre meilleur pari en ce moment.

Notez que la valprise en charge par Lombokainsi sans modifier ou créer un fichier lombok.config.

BullyWiiPlaza
la source
2

Vous pouvez, dans Java 10, mais uniquement pour les variables locales , ce qui signifie,

Vous pouvez,

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

Mais je ne peux pas,

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

Consultez les spécifications pour plus d'informations.

Antho Christen
la source
2
Ceci est une erreur. varpeut être utilisé pour de nombreuses formes de types non dénotables, y compris les types de capture, les types d'intersection et les types de classe anonymes. Et, à partir de Java 11, il peut également être appliqué aux paramètres lambda.
Brian Goetz
0

En général, vous pouvez utiliser la classe Object pour n'importe quel type, mais vous devez effectuer une conversion de type plus tard!

par exemple:-

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
la source
Aditya, veuillez vérifier toutes vos autres réponses. Beaucoup d'entre eux ont -1 et probablement pour une bonne raison. Ne vous contentez pas de poster quoi que ce soit si vous n'êtes pas sûr que c'est correct.
user1306322
@ user1306322 quel est le problème dans ma réponse! pouvez-vous élaborer? ne pouvons-nous pas utiliser la classe Object pour tous les types de données?
Aditya Kumar
Objet objet = 12; Objet object1 = "Aditya"; Objet 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
Le problème est que vous n'avez pas compris la question. La question n'était pas "comment faire fonctionner", mais "y a-t-il quelque chose comme ça". Vous répondez à la mauvaise question. Avec le varmot maintenant officiellement dans la langue, votre réponse fait également référence à la manière désormais démodée.
user1306322