¿Cuál es el equivalente de la palabra clave C # 'var' en Java?

264

Un uso de la palabra clave var en C # es la declaración de tipo implícita. ¿Cuál es la sintaxis equivalente de Java para var ?

Arturo
fuente
44
val(o var) si usa un lenguaje particular de "reemplazo de Java" ;-)
66
@pst: eso sería Scala? Hm sí, lo es.
rsenna
Para IntelliJ, envié esto como una solicitud de función: youtrack.jetbrains.com/issue/IDEA-102808 El IDE podría colapsar el código para mostrar val o var, aunque el código subyacente no lo tuviera.
Jon Onstott
@ Jon He pirateado algo para IntelliJ, mira mi respuesta .
balpha
3
Ahora hay una propuesta para que esta característica se incluya en Java - openjdk.java.net/jeps/286
McGin

Respuestas:

248

No hay ninguno. Por desgracia, debe escribir el nombre completo del tipo.

Editar: 7 años después de su publicación, varse agregó inferencia de tipo para variables locales (con ) en Java 10.

Editar: 6 años después de ser publicado, para recopilar algunos de los comentarios a continuación:

  • La razón por la que C # tiene la varpalabra clave es porque es posible tener Tipos que no tienen nombre en .NET. P.ej:

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

    En este caso, sería imposible darle un tipo apropiado myData. Hace 6 años, esto era imposible en Java (todos los tipos tenían nombres, incluso si eran extremadamente verbosos y poco amables). No sé si esto ha cambiado mientras tanto.

  • varNo es lo mismo que dynamic. varLas iables siguen siendo 100% de tipo estático Esto no compilará:

    var myString = "foo";
    myString = 3;
    
  • varTambién es útil cuando el tipo es obvio por el contexto. Por ejemplo:

    var currentUser = User.GetCurrent();

    Puedo decir que en cualquier código del que soy responsable, currentUsertiene una Userclase o derivada. Obviamente, si su implementación de User.GetCurrentreturn an int, entonces quizás esto sea en detrimento de usted.

  • Esto no tiene nada que ver var, pero si tiene jerarquías de herencia extrañas en las que sombrea métodos con otros métodos (por ejemplo new public void DoAThing()), no olvide que los métodos no virtuales se ven afectados por el Tipo con el que se convierten.

    No puedo imaginar un escenario del mundo real en el que esto sea indicativo de un buen diseño, pero esto puede no funcionar como se espera:

    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
    

    Como se indicó, los métodos virtuales no se ven afectados por esto.

  • No, no hay una forma no torpe de inicializar a varsin una variable real.

    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

    En este caso, simplemente hazlo a la antigua usanza:

    object foo6;
Mike Caron
fuente
11
@ Mike Caron: C # tiene llamadas [virtuales] no virtuales y los operadores no son virtuales, así que ... var p = new X(); p.Z()no es lo mismo que SuperX p = new X(); p.Z()para todas las X y SuperX, aunque X : SuperX. Con varel tipo estático de psiempre está Xen el primer ejemplo anterior, pero siempre SuperXen el segundo ejemplo. Una diferencia sutil pero importante a tener en cuenta. Pero su respuesta es muy correcta :-)
200
@ Jon Hanna: varno deja el código menos claro. Más bien lo contrario en mi opinión. ¿Por qué, por ejemplo, escribe el tipo dos (o incluso tres) veces en la misma fila cuando lo declara y lo instancia ( RadioButton radioButton = new RadioButton();)? varte hace pensar dos veces cuando estás nombrando tus variables porque centra la atención en la funcionalidad en lugar del tipo (por ejemplo, UserCollection collection = new userRepository.GetUsers();se convierte en algo más natural var users = userRepository.GetUsers();). Si crees que varno está claro es porque no está acostumbrado.
Martin Odhelius
44
@MartinOdhelius vardefinitivamente puede dejar bien en claro el código, pero también puede hacer que no esté claro si se usa mal; como muchas opciones de formato. El balance difiere dependiendo de cuánto use objetos anónimos y genéricos, ninguno de los cuales existía en .NET 1.0, lo que lo hace menos útil como una palabra clave hipotética en la primera versión de C♯. Solo nombraría un RadioButton radioButtonen el caso de un método de fábrica o auxiliar donde lo único significativo sobre el botón era que era un RadioButton, de lo contrario, eso es una locura con o sin var.
Jon Hanna
66
@ Jon Hanna: Una vez fui tan crítico con varusted como usted, si no más, pero he cambiado de opinión, y tal vez sea tan simple como una cuestión de opiniones diferentes, porque todavía creo que está equivocado cuando dice que es un error. no importa cuánto esté usando objetos anónimos y genéricos;) La declaración de tipo suele ser solo ruido de código, si no puede entender el código sin él, el código probablemente no esté claro en ninguno de los casos.
Martin Odhelius
3
Estás confundiendo var con tipos anónimos . varsimplemente le pide al compilador que infiera el tipo de la asignación; Es azúcar sintáctico. Al principio era escéptico al respecto, pero lo uso religiosamente y aún no he encontrado un momento en el que haya causado confusión. Elimina la redundancia al crear instancias y elimina la necesidad de verificar el tipo al hacer referencia. No hay equivalente de JAVA a partir de JAVA 9.
Robear
46

Si agrega Lombok a su proyecto, puede usar su palabra clave val .

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

darthtrevino
fuente
1
@rightfold: los objetos cuya referencia finalno es necesariamente inmutable. Considerefinal StringBuilder strB = new StringBuilder("My reference is final"); strB.append("I'm not immutable");
Matthias Braun
1
Desde lombok v1.16.12 también hay soporte experimental para var. projectlombok.org/features/experimental/var.html
Roel Spilker
@MatthiasBraun su ejemplo está mal. En este caso, la clase StringBuilder en sí es inmutable, solo agrega valor de cadena a su estructura interna utilizando el método, esto es totalmente legal.
Andzej Maciusovic
27

JEP - Propuesta de mejora de JDK

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

JEP 286: Inferencia de tipo variable local

Autor Brian Goetz

// Goals:
var list = new ArrayList<String>();  // infers ArrayList<String>
var stream = list.stream();          // infers Stream<String>
blueberry0xff
fuente
¿Qué versión de Java? 10?
Peter Mortensen
@PeterMortensen Sí. JEP 286 ha sido aceptado y publicado en JDK 10 (ver 286 en Características en openjdk.java.net/projects/jdk/10 ).
Justin Albano
20

He preparado un complemento para IntelliJ que, en cierto modo, te ofrece varen Java. Es un truco, por lo que se aplican las exenciones de responsabilidad habituales, pero si usa IntelliJ para su desarrollo de Java y desea probarlo, está en https://bitbucket.org/balpha/varsity .

balpha
fuente
Sería genial tener un atajo de teclado para plegar / desplegar tipos de declaración en el editor actual. Gran complemento sin embargo.
tecla
2
@hotkey Utiliza el plegado de código integrado de IntelliJ, por lo que puede desplegar todo con Ctrl-Shift-NumPadPlus. Cuando el cursor está en una línea que contiene una declaración de variable plegada, puede Ctrl-NumPadPlus y Ctrl-NumPadMinus para plegar / desplegar las declaraciones en el método actual. Doblar todas las declaraciones es un poco incómodo, tiene doblar todo (Ctrl-Shift-NumPadMinus) y luego desplegar todo nuevamente (Ctrl-Shift-NumPadPlus).
balpha
18

Con el lanzamiento de JDK 10 el 20 de marzo, Java ahora incluye un varnombre de tipo reservado (no una palabra clave, ver más abajo) como se especifica en JEP 286 . Para las variables locales, lo siguiente ahora es válido en Java 10 o superior:

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

El varnombre de tipo reservado en Java es casi idéntico a la varpalabra clave en C #, ya que ambos permiten la escritura implícita (consulte a continuación las diferencias importantes). varen Java solo se puede usar para la inferencia de tipo implícita en los siguientes contextos (como se enumera en JEP 286: Objetivos ):

  • variables locales con inicializadores
  • índices en el bucle for mejorado
  • locales declarados en un bucle for tradicional

Por var lo tanto , no se puede usar para campos, tipos de retorno, nombres de clase o nombres de interfaz. Su fundamento es eliminar la necesidad de incluir nombres de tipo largos al declarar y definir variables locales, como se indica en JEP 286 (escrito por Brian Goetz):

Buscamos mejorar la experiencia del desarrollador al reducir la ceremonia asociada con la escritura de código Java, al tiempo que se mantiene el compromiso de Java con la seguridad de tipos estáticos, al permitir a los desarrolladores eludir la declaración de manifiesto a menudo innecesaria de los tipos de variables locales.

var Alcance en Java

Cabe señalar que varno es una palabra clave en Java, sino un nombre de tipo reservado. Como se cita de JEP 286:

El identificador var no es una palabra clave; en cambio es un nombre de tipo reservado. Esto significa que el código que usa var como variable, método o nombre del paquete no se verá afectado; el código que usa var como clase o nombre de interfaz se verá afectado (pero estos nombres son raros en la práctica, ya que violan las convenciones de nomenclatura habituales).

Tenga en cuenta que, dado que vares un nombre de tipo reservado y no una palabra clave, todavía se puede usar para nombres de paquetes, nombres de métodos y nombres de variables (junto con su nueva función de interferencia de tipos). Por ejemplo, los siguientes son todos ejemplos de usos válidos de varen Java:

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

Como se cita de JEP 286:

Este tratamiento se restringiría a variables locales con inicializadores, índices en el bucle for mejorado y locales declarados en un bucle for tradicional; no estaría disponible para formales de método, formales de constructor, tipos de retorno de método, campos, formales de captura o cualquier otro tipo de declaración de variable.

Diferencias entre varen Java y C

Esta es una diferencia notable entre varC # y Java que incluye lo siguiente: varse puede usar como nombre de tipo en C # pero no se puede usar como nombre de clase o nombre de interfaz en Java. De acuerdo con la documentación de C # (Variables locales escritas implícitamente) :

Si un tipo llamado varestá dentro del alcance, la varpalabra clave se resolverá con ese nombre de tipo y no se tratará como parte de una declaración de variable local tipada implícitamente.

La capacidad de usar varcomo nombre de tipo en C # crea cierta complejidad e introduce algunas reglas de resolución complejas, que varJava evita al deshabilitar varcomo nombre de clase o interfaz. Para obtener información sobre las complejidades de los varnombres de tipo en C #, consulte Restricciones que se aplican a las declaraciones de variables escritas implícitamente . Para obtener más información sobre la justificación de la decisión de determinación del alcance de `var en Java, consulte JEP 286: Opciones de determinación del alcance .

Justin Albano
fuente
¿Hay alguna diferencia entre Java y C # en que no se puede usar varpara campos o tipos de retorno? ¿Por qué es importante tener en cuenta?
user1306322
@ user1306322 En ese contexto, no. varen Java no se puede usar para campos o tipos de retorno. Esto es importante porque esta restricción hace que sea varsensible al contexto, donde solo se puede usar en algunos contextos (variables locales) y no en otros. Esto no es necesariamente una diferencia entre Java y C # que debe tenerse en cuenta, pero es una restricción importante en general cuando se usa varen Java.
Justin Albano
Acabo de mirar hacia arriba y parece que en c # puedes hacer varun nombre de clase y usarlo como tal. Técnicamente es una "palabra clave de contexto" en el caso de c #, pero en Java parece que no puede hacer lo mismo. Corrígeme si me equivoco.
user1306322
1
Estás en lo correcto. No puede usarlo varcomo un nombre de clase o un nombre de interfaz en Java (que de todos modos no es común), pero puede usarlo para nombres de variables, nombres de métodos y nombres de paquetes. Por ejemplo, var var = 1;es una declaración válida de Java, pero tratando de declarar una clase que public class var {}resulta en un error: as of release 10, 'var' is a restricted local variable type and cannot be used for type declarations. He actualizado la respuesta anterior para entrar en más detalles sobre la lógica detrás varde Java y sus diferencias con varC #.
Justin Albano
11

Se admitirá en JDK 10. Incluso es posible verlo en acción en la compilación de acceso temprano .

El JEP 286 :

Mejore el lenguaje Java para extender la inferencia de tipos a declaraciones de variables locales con inicializadores.

Entonces ahora en lugar de escribir:

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

Usted escribe:

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

Notas:

  • varahora es un nombre de tipo reservado
  • ¡Java sigue comprometido con la escritura estática!
  • Solo se puede usar en declaraciones de variables locales

Si desea probarlo sin instalar Java en su sistema local, creé una imagen Docker con JDK 10 instalado:

$ 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
fuente
3
Tenga cuidado, el código que proporcionó (antes / después var) no es equivalente. En el varejemplo listes de tipo ArrayList, no a List.
Gili
8

Una solución simple (suponiendo que esté usando un IDE decente) es simplemente escribir 'int' en todas partes y luego configurarlo para usted.

De hecho, acabo de agregar una clase llamada 'var' para no tener que escribir algo diferente.

El código todavía es demasiado detallado, ¡pero al menos no tiene que escribirlo!

JonnyRaa
fuente
Cuando dice "IDE decente", ¿se excluye Eclipse *? - Esto no parece funcionar en Luna (al menos cuando lo probé int) - ¿Me estoy perdiendo algo? (*: aunque nunca llamaría a Eclipse un IDE decente, no puedo juzgar por los demás ...)
BrainSlugs83
@ BrainSlugs83 no sé Estoy usando IDEA, realmente no usé eclipse antes. ¿No corrige los tipos para ti? Estoy acostumbrado a c # / visual studio / resharper, que es como IDEA, ¡excepto que realmente funciona correctamente! En todos los jetbrains, puede presionar alt-enter para obtener una lista de sugerencias cuando hay un error, por lo que configurar type to int introduce un error que puede alt-enter y hacer que
clasifique
5

Puedes echar un vistazo a Kotlin por JetBrains, pero es val. no var.

Artiom
fuente
44
Kotlin tiene val y var. val es equivalente a declarar una variable final en java, var permite la reasignación.
samlewis
5

Java 10 obtuvo inferencia de tipo de variable local, por lo que ahora tiene lo varque es más o menos equivalente a C # one (que yo sepa).

También puede inferir tipos no denotables (tipos que el programador no pudo nombrar en ese lugar; aunque los tipos que no son denotables son diferentes). Vea, por ejemplo, Trucos con varclases anónimas (que nunca debe usar en el trabajo) .

La única diferencia que pude encontrar es que en C #,

Si un tipo llamado var está dentro del alcance, la palabra clave var se resolverá con ese nombre de tipo y no se tratará como parte de una declaración de variable local tipada implícitamente.

En Java 10 varno es un nombre de tipo legal.

Alexey Romanov
fuente
@Lii Sí, no recuerdo lo que quise decir aquí, eliminado.
Alexey Romanov
¡Excelente! ¡Eliminaré mi comentario para limpiar el historial!
Lii
4

A partir del 10 de Java, el equivalente es ... var.

Brian Goetz
fuente
¿Hay alguna diferencia? Quiero decir que sabes mejor que escribir respuestas cortas como esta, con tu nivel de representante n todos. Y seguramente debe haber algunas diferencias.
user1306322
@ user1306322 ¡Esa es una pregunta completamente diferente! Puede verificar la etiqueta java-10, ya que muchos aspectos de esto ya se han solicitado.
Brian Goetz el
Bueno, esta es la pregunta a tener en cuenta si buscas en Google, ya que es lo primero y está vinculado en cada publicación relacionada en la barra lateral. Entonces, supongo que si conoce esa pregunta separada que la responde, al menos podría vincularla o incluir partes de ella en su respuesta.
user1306322
3

Sé que esto es más antiguo, pero ¿por qué no crear una clase var y crear constructores con diferentes tipos y dependiendo de qué constructores se invoque, obtienes var con diferentes tipos. Incluso podría incorporar métodos para convertir un tipo a otro.

Sebastian Zaba
fuente
3

Lombokadmite var pero todavía está clasificado como experimental:

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

Aquí hay una trampa que debes evitar cuando tratas de usarlo IntelliJ IDEA. Parece funcionar como se esperaba, aunque incluye la finalización automática y todo. Hasta que haya una solución "no hacky" (por ejemplo, debido a JEP 286: Inferencia de tipo variable local ), esta podría ser su mejor opción en este momento.

Tenga en cuenta que también vales compatible Lomboksin modificar o crear a lombok.config.

BullyWiiPlaza
fuente
2

Puede, en Java 10, pero solo para variables locales , es decir,

Usted puede,

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

Pero no puedo

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

Echa un vistazo a las especificaciones para más información.

Antho Christen
fuente
2
Esto es incorrecto. varse puede usar para muchas formas de tipos no denotables, incluidos los tipos de captura, los tipos de intersección y los tipos de clase anónimos. Y, a partir de Java 11, también se puede aplicar a los parámetros lambda.
Brian Goetz
0

En general, puede usar la clase Object para cualquier tipo, ¡pero debe hacer la conversión de tipos más tarde!

p.ej:-

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
fuente
Aditya, por favor revisa todas tus otras respuestas. Muchos de ellos tienen -1 y probablemente por una buena razón. No publiques lo que sea si no estás seguro de que sea correcto.
user1306322
@ user1306322 cuál es el problema en mi respuesta! puedes elaborar? ¿No podemos usar la clase Object para todo tipo de datos?
Aditya Kumar el
Objeto objeto = 12; Object object1 = "Aditya"; Objeto objeto2 = 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
El problema es que no entendiste la pregunta. La pregunta no era "cómo hacer que esto funcione", sino "¿hay algo como esto". Respondes la pregunta equivocada. Con la varpalabra ahora oficialmente en el idioma, su respuesta también se refiere a la forma ya pasada de moda.
user1306322