Qual é o equivalente da palavra-chave C # 'var' em Java?

264

Um uso da palavra-chave var em C # é uma declaração implícita de tipo. Qual é a sintaxe equivalente a Java para var ?

Arturo
fonte
4
val(ou var) se você usa uma linguagem "Java de substituição" específica ;-) #
6
@ pst: isso seria Scala? Hum, é sim.
rsenna
Para o IntelliJ, enviei isso como uma solicitação de recurso: youtrack.jetbrains.com/issue/IDEA-102808 O IDE poderia recolher o código para mostrar val ou var, mesmo que o código subjacente não o tivesse.
Jon Onstott
@ Jon hackeei algo juntos para IntelliJ, veja minha resposta .
balpha
3
Agora existe uma proposta para esse recurso ser incluído no Java - openjdk.java.net/jeps/286
McGin 13/16

Respostas:

248

Não há nenhum. Infelizmente, você precisa digitar o nome completo do tipo.

Edit: 7 anos após o lançamento, a inferência de tipo para variáveis ​​locais (com var) foi adicionada no Java 10.

Editar: 6 anos após a publicação, para coletar alguns dos comentários abaixo:

  • O motivo pelo qual C # tem a varpalavra-chave é que é possível ter tipos que não têm nome no .NET. Por exemplo:

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

    Nesse caso, seria impossível atribuir um tipo adequado myData. Há 6 anos, isso era impossível em Java (todos os tipos tinham nomes, mesmo que fossem extremamente detalhados e pouco controlados). Não sei se isso mudou nesse meio tempo.

  • varnão é o mesmo que dynamic. varOs dados ainda são 100% digitados estaticamente. Isso não será compilado:

    var myString = "foo";
    myString = 3;
  • vartambém é útil quando o tipo é óbvio no contexto. Por exemplo:

    var currentUser = User.GetCurrent();

    Posso dizer que em qualquer código pelo qual sou responsável, currentUserhá uma Userclasse ou classe derivada. Obviamente, se sua implementação de User.GetCurrentretornar um int, talvez isso seja um prejuízo para você.

  • Isso não tem nada a ver com isso var, mas se você tiver hierarquias de herança estranhas nas quais sombreia métodos com outros métodos (por exemplo new public void DoAThing()), não esqueça que métodos não virtuais são afetados pelo tipo em que são convertidos.

    Não consigo imaginar um cenário do mundo real em que isso seja indicativo de bom design, mas isso pode não funcionar como o esperado:

    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 indicado, os métodos virtuais não são afetados por isso.

  • Não, não há uma maneira não desajeitada de inicializar a varsem uma variável 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

    Nesse caso, faça da maneira antiga:

    object foo6;
Mike Caron
fonte
11
@ Mike Caron: C # tem [padrão] chamadas não virtuais e os operadores não são virtuais, portanto ... var p = new X(); p.Z()não é o mesmo que SuperX p = new X(); p.Z()para todos os X e SuperX, apesar de tudo X : SuperX. Com varo tipo estático,p está sempre Xno primeiro exemplo acima, mas sempre SuperXno segundo exemplo. Uma diferença sutil, mas importante, para estar ciente. Mas a sua resposta está muito correta :-) #
200
@ Jon Hanna: varnão torna o código menos claro. Pelo contrário, na minha opinião. Por que, por exemplo, escreva o tipo duas (ou até três) vezes na mesma linha quando você a declara e a instancia ( RadioButton radioButton = new RadioButton();)? varfaz com que você pense duas vezes ao nomear suas variáveis, porque ele se concentra mais na funcionalidade do que no tipo (por exemplo, UserCollection collection = new userRepository.GetUsers();mais naturalmente se transforma var users = userRepository.GetUsers();). Se você acha que varnão está claro, é porque não está acostumado.
Martin Odhelius
4
Definitivamente, o @MartinOdhelius varpode deixar bem claro o código usado, mas também pode deixar claro o mau uso; como muitas opções de formatação. O saldo varia de acordo com o quanto você usa objetos e genéricos anônimos, nenhum dos quais existia no .NET 1.0, tornando-o menos útil como uma palavra-chave hipotética na primeira versão do C♯. Eu nomearia apenas a RadioButton radioButtonno caso de um método de fábrica ou auxiliar, onde a única coisa significativa sobre o botão era que era um RadioButton, caso contrário, isso é loucura com ou sem var.
Jon Hanna
6
@ Jon Hanna: Eu já fui tão crítico varquanto você, se não mais, mas mudei de opinião, e talvez seja tão simples quanto uma questão de opiniões diferentes, porque ainda acho que você está errado quando diz que é um não importa o quanto você esteja usando objetos e genéricos anônimos;) A declaração de tipo geralmente é apenas um ruído de código; se você não conseguir entender o código sem ele, o código provavelmente não será claro nos dois casos.
Martin Odhelius
3
Você está confundindo var com tipos anônimos . varele próprio simplesmente pede ao compilador para inferir o tipo da atribuição; é açúcar sintático. Eu era cético a princípio, mas o uso religiosamente e ainda tenho que encontrar um momento em que isso causou confusão. Remove a redundância ao instanciar e remove a necessidade de verificar o tipo ao fazer referência. Não há equivalente JAVA como de JAVA 9.
Robear
46

Se você adicionar o Lombok ao seu projeto, poderá usar a palavra-chave val .

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

darthtrevino
fonte
1
@ rightfold: Objetos cuja referência é finalnão são necessariamente imutáveis. Considerefinal StringBuilder strB = new StringBuilder("My reference is final"); strB.append("I'm not immutable");
Matthias Braun
1
Desde o lombok v1.16.12, também há suporte experimental para var. projectlombok.org/features/experimental/var.html
Roel Spilker
@MatthiasBraun, seu exemplo está errado. Nesse caso, a própria classe StringBuilder é imutável; você apenas adiciona valor da string à sua estrutura interna usando o método, isso é totalmente legal.
Andzej Maciusovic 11/08/19
27

JEP - Proposta de aprimoramento do JDK

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

JEP 286: Inferência de tipo variável local

Autor Brian Goetz

// Goals:
var list = new ArrayList<String>();  // infers ArrayList<String>
var stream = list.stream();          // infers Stream<String>
blueberry0xff
fonte
Qual versão do Java? 10?
Peter Mortensen
@PeterMortensen Sim. O JEP 286 foi aceito e publicado no JDK 10 (consulte 286 em Recursos em openjdk.java.net/projects/jdk/10 ).
Justin Albano
20

Eu criei um plugin para o IntelliJ que, de certa forma, fornece a você varem Java. É um hack, então as isenções de responsabilidade usuais se aplicam, mas se você usa o IntelliJ para o seu desenvolvimento Java e deseja experimentá-lo, é em https://bitbucket.org/balpha/varsity .

balpha
fonte
Seria ótimo ter um atalho de teclado para dobrar / desdobrar tipos de declaração no editor atual. Ótimo plugin embora.
hotkey
2
@hotkey Utiliza a dobra de código interna do IntelliJ, para que você possa desdobrar tudo com o Ctrl-Shift-NumPadPlus. Quando o cursor está em uma linha que contém uma declaração de variável dobrada, você pode Ctrl-NumPadPlus e Ctrl-NumPadMinus para dobrar / desdobrar as declarações no método atual. Dobrar todas as declarações é um pouco estranho, você dobra tudo (Ctrl-Shift-NumPadMinus) e desdobra tudo novamente (Ctrl-Shift-NumPadPlus).
balpha
18

Com o lançamento do JDK 10 em 20 de março, o Java agora inclui um varnome de tipo reservado (não uma palavra-chave - veja abaixo), conforme especificado no JEP 286 . Para variáveis ​​locais, o seguinte agora é válido no Java 10 ou superior:

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

O varnome do tipo reservado em Java é quase idêntico à varpalavra - chave em C #, pois ambos permitem digitação implícita (veja abaixo diferenças importantes). varem Java pode ser usado apenas para inferência implícita de tipo nos seguintes contextos (conforme enumerado no JEP 286: Objetivos ):

  • variáveis ​​locais com inicializadores
  • índices no loop for aprimorado
  • locais declarados em um loop for tradicional

Portanto, var não pode ser usado para campos, tipos de retorno, nomes de classe ou nomes de interface. Sua lógica é remover a necessidade de incluir nomes de tipo longos ao declarar e definir variáveis ​​locais, conforme declarado no JEP 286 (de autoria de Brian Goetz):

Procuramos melhorar a experiência do desenvolvedor, reduzindo a cerimônia associada à escrita do código Java, mantendo o compromisso do Java com a segurança de tipo estático, permitindo que os desenvolvedores excluam a declaração manifesta muitas vezes desnecessária dos tipos de variáveis ​​locais.

var Escopo em Java

Note-se que varnão é uma palavra-chave em Java, mas um nome de tipo reservado. Conforme citado no JEP 286:

O identificador var não é uma palavra-chave; em vez disso, é um nome de tipo reservado. Isso significa que o código que usa var como uma variável, método ou nome do pacote não será afetado; o código que usa var como nome de classe ou interface será afetado (mas na prática esses nomes são raros, pois violam as convenções de nomenclatura comuns).

Observe que, como varé um nome de tipo reservado e não uma palavra-chave, ele ainda pode ser usado para nomes de pacotes, nomes de métodos e nomes de variáveis ​​(junto com sua nova função de interferência de tipo). Por exemplo, todos os exemplos a seguir são de usos válidos varem Java:

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

Conforme citado no JEP 286:

Esse tratamento seria restrito a variáveis ​​locais com inicializadores, índices no loop for aprimorado e locais declarados em um loop for tradicional; não estaria disponível para formals de método, formals de construtor, tipos de retorno de método, campos, formals de captura ou qualquer outro tipo de declaração de variável.

Diferenças entre varem Java e C

Essa é uma diferença notável entre varC # e Java: o varpode ser usado como um nome de tipo em C #, mas não pode ser usado como um nome de classe ou de interface em Java. De acordo com a documentação do C # (variáveis ​​locais implicitamente digitadas) :

Se um tipo nomeado varestiver no escopo, a varpalavra - chave será resolvida com esse nome de tipo e não será tratada como parte de uma declaração de variável local digitada implicitamente.

A capacidade de usar varcomo um nome de tipo em C # cria alguma complexidade e introduz algumas regras complexas de resolução, que são evitadas varno Java ao proibir varcomo nome de classe ou interface. Para obter informações sobre as complexidades dos varnomes de tipos em C #, consulte Restrições se aplicam a declarações de variáveis de tipo implícito . Para obter mais informações sobre a lógica por trás da decisão de escopo para `var em Java, consulte JEP 286: Opções de Escopo .

Justin Albano
fonte
Existe alguma diferença entre Java e c # em que você não pode usar varcampos ou tipos de retorno? Por que é importante notar?
precisa saber é o seguinte
@ user1306322 Nesse contexto, não. varem Java não pode ser usado para campos ou tipos de retorno. Isso é importante porque essa restrição torna varsensível ao contexto, onde só pode ser usada em alguns contextos (variáveis ​​locais) e não em outros. Essa não é necessariamente uma diferença entre Java e C # que deve ser observada, mas uma restrição importante em geral quando usada varem Java.
23630 Justin Albano
Eu apenas olhei para cima e parece que em c # você pode criar varum nome de classe e usá-lo como tal. Tecnicamente, é uma "palavra-chave de contexto" no caso de c #, mas em Java parece que você não pode fazer o mesmo. Corrija-me se eu estiver errado.
precisa saber é o seguinte
1
Você está certo. Você não pode usar varcomo um nome de classe ou um nome de interface em Java (o que não é comum de qualquer maneira), mas pode ser usado para nomes de variáveis, nomes de métodos e nomes de pacotes. Por exemplo, var var = 1;é uma declaração Java válido, mas tentando declarar uma classe como public class var {}resulta em um erro: as of release 10, 'var' is a restricted local variable type and cannot be used for type declarations. Atualizei a resposta acima para entrar em mais detalhes sobre a lógica por trás vardo Java e suas diferenças com o varC #.
Justin Albano
11

Ele será suportado no JDK 10. É ainda possível vê-lo em ação na compilação de acesso antecipado .

O JEP 286 :

Aprimore a linguagem Java para estender a inferência de tipo para declarações de variáveis ​​locais com inicializadores.

Então agora, em vez de escrever:

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

Você escreve:

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

Notas:

  • varagora é um nome de tipo reservado
  • Java ainda está comprometido com a digitação estática!
  • Só pode ser usado em declarações de variáveis locais

Se você quiser experimentá-lo sem instalar o Java em seu sistema local, criei uma imagem do Docker com o 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
fonte
3
Cuidado, o código que você forneceu (antes / depois var) não é equivalente. No varexemplo listé do tipo ArrayList, não a List.
Gili
8

Uma solução simples (supondo que você esteja usando um IDE decente) é apenas digitar 'int' em todos os lugares e depois definir o tipo para você.

Na verdade, acabei de adicionar uma classe chamada 'var' para não precisar digitar algo diferente.

O código ainda é muito detalhado, mas pelo menos você não precisa digitá-lo!

JonnyRaa
fonte
Quando você diz "IDE decente", o Eclipse * é excluído? - isso não parece funcionar em Luna (pelo menos quando eu tentei int) - estou perdendo alguma coisa? (*: Embora eu nunca chamaria Eclipse uma IDE decente, não posso julgar por outros ...)
BrainSlugs83
@ BrainSlugs83 não sei Eu estou usando o IDEA, realmente não usei o eclipse antes. Não corrige tipos para você? Estou acostumado a c # / visual studio / resharper, que é como o IDEA, exceto que realmente funciona corretamente! Em todos os jetbrains, você pode pressionar alt-enter para obter uma lista de sugestões quando houver um erro - portanto, definir type para int introduz um erro que você pode pressionar alt-enter e ordená-lo para classificar o tipo
JonnyRaa
5

Você pode dar uma olhada no Kotlin by JetBrains, mas é val. não var.

Artiom
fonte
4
Kotlin tem val e var. val é equivalente a declarar uma variável final em java, var permite a reatribuição.
samlewis
5

O Java 10 obteve inferência de tipo de variável local, agora ele possui varpraticamente o equivalente ao C # one (tanto quanto sei).

Também pode inferir tipos não denotáveis ​​(tipos que não puderam ser nomeados nesse local pelo programador; apesar de que tipos não denotáveis ​​são diferentes). Veja, por exemplo, Truques com varclasses anônimas (que você nunca deve usar no trabalho) .

A única diferença que pude encontrar é que em C #,

Se um tipo chamado var estiver no escopo, a palavra-chave var será resolvida com esse nome de tipo e não será tratada como parte de uma declaração de variável local digitada implicitamente.

No Java 10 varnão é um nome de tipo legal.

Alexey Romanov
fonte
@ Li Sim, não me lembro do que quis dizer aqui, removido.
Alexey Romanov
Ótimo! Removerá meu comentário para limpar a história!
Lii
4

A partir de Java 10, o equivalente é ... var.

Brian Goetz
fonte
Existem quaisquer diferenças? Quero dizer, você sabe que não deve escrever respostas curtas como esta, com o seu nível de representante em todos. E certamente deve haver algumas diferenças.
precisa saber é o seguinte
@ user1306322 Essa é uma pergunta totalmente separada! Você pode verificar a tag java-10, pois muitos aspectos já foram solicitados.
Brian Goetz
Bem, esta é a questão a ser examinada se você pesquisar no Google, pois ele vem primeiro e está vinculado a todas as postagens relacionadas na barra lateral. Portanto, suponho que, se você conhece uma pergunta separada que a responde, você pode pelo menos vincular-se a ela ou incluir partes dela em sua resposta.
precisa saber é o seguinte
3

Eu sei que isso é mais antigo, mas por que não criar uma classe var e criar construtores com tipos diferentes e dependendo de quais construtores são chamados, você obtém var com tipos diferentes. Você pode até criar métodos para converter um tipo em outro.

Sebastian Zaba
fonte
3

Lomboksuporta var, mas ainda é classificado 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);

Aqui está uma armadilha a evitar ao tentar usá-lo IntelliJ IDEA. Parece funcionar como esperado, incluindo a conclusão automática e tudo mais. Até que exista uma solução "não-hacky" (por exemplo, devido ao JEP 286: Inferência de tipo de variável local ), essa pode ser sua melhor aposta agora.

Observe que também valé Lomboksuportado sem modificar ou criar um lombok.config.

BullyWiiPlaza
fonte
2

Você pode, no Java 10, mas apenas para variáveis locais , significando,

Você pode,

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

Mas não pode,

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

Confira as especificações para mais informações.

Antho Christen
fonte
2
Isto está incorreto. varpode ser usado para muitas formas de tipos não denotáveis, incluindo tipos de captura, tipos de interseção e tipos de classe anônimos. E, a partir do Java 11, também pode ser aplicado aos parâmetros lambda.
Brian Goetz
0

Em geral, você pode usar a classe Object para qualquer tipo, mas pode fazer a conversão de tipo mais tarde!

por exemplo:-

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
fonte
Aditya, verifique todas as suas outras respostas. Muitos deles têm -1 e provavelmente por um bom motivo. Não poste apenas o que quiser, se não tiver certeza de que está correto.
precisa saber é o seguinte
@ user1306322 qual é o problema na minha resposta! você pode elaborar? não podemos usar a classe Object para todos os tipos de dados?
Aditya Kumar #
Objeto objeto = 12; Objeto 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 #
O problema é que você não entendeu a pergunta. A questão não era "como fazer isso funcionar", mas "existe algo assim". Você responde a pergunta errada. Com a varpalavra agora oficialmente no idioma, sua resposta também se refere à maneira antiquada.
precisa saber é o seguinte