Что эквивалентно ключевому слову C # 'var' в Java?

264

Одним из применений ключевого слова var в C # является неявное объявление типа. Каков эквивалентный синтаксис Java для var ?

Arturo
источник
4
val(или var) если вы используете конкретный язык «замены Java» ;-)
6
@pst: это будет Scala? Хм да, это так.
rsenna
Для IntelliJ я отправил это как запрос функции: youtrack.jetbrains.com/issue/IDEA-102808 IDE может свернуть код, чтобы показать val или var, даже если базовый код его не имеет.
Джон Онстотт
@Jon Я кое-что взломал для IntelliJ, посмотри мой ответ .
Балфа
3
Теперь есть предложение включить эту функцию в Java - openjdk.java.net/jeps/286
McGin

Ответы:

248

Здесь ничего нет. Увы, вы должны ввести полное имя типа.

Редактировать: 7 лет после публикации, вывод типа для локальных переменных (с var) был добавлен в Java 10.

Изменить: через 6 лет после публикации, чтобы собрать некоторые комментарии ниже:

  • Причина, по которой C # имеет varключевое слово, заключается в том, что в .NET могут быть типы, которые не имеют имени. Например:

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

    В этом случае было бы невозможно дать правильный тип myData. 6 лет назад это было невозможно в Java (у всех типов были имена, даже если они были чрезвычайно многословны и непривычны). Я не знаю, изменилось ли это в то же время.

  • varэто не то же самое, что dynamic. varТаблицы все еще на 100% статически типизированы. Это не скомпилирует:

    var myString = "foo";
    myString = 3;
  • varтакже полезно, когда тип очевиден из контекста. Например:

    var currentUser = User.GetCurrent();

    Я могу сказать, что в любом коде, за который я отвечаю, currentUserесть Userкласс или производный класс. Очевидно, что если ваша реализация User.GetCurrentвернула int, то, возможно, это нанесет вам ущерб.

  • Это не имеет ничего общего var, но если у вас есть странные иерархии наследования, где вы скрываете методы другими методами (например new public void DoAThing()), не забывайте, что на не виртуальные методы влияет Тип, к которому они приводятся.

    Я не могу представить сценарий реального мира, где это свидетельствует о хорошем дизайне, но это может работать не так, как вы ожидаете:

    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

    Как указано, на виртуальные методы это не влияет.

  • Нет, нет неуклюжего способа инициализации a varбез фактической переменной.

    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

    В этом случае просто сделайте это по старинке:

    object foo6;
Майк Карон
источник
11
Caron @ Mike: C # есть [ по умолчанию] невиртуальные вызовы и операторы не виртуальные , так ... var p = new X(); p.Z()это не то же самое , как SuperX p = new X(); p.Z()для всех X и и SuperX, несмотря на то X : SuperX. С varв статическом типе из pвсегда Xв первом примере выше, но всегда SuperXво втором примере. Тонкое, но важное отличие, о котором нужно знать. Но ваш ответ очень правильный :-)
200
@ Джон Ханна: varне делает код менее понятным. Скорее наоборот на мой взгляд. Зачем, например, писать тип два (или даже три) раза в одной строке, когда вы объявляете и создаете его экземпляр ( RadioButton radioButton = new RadioButton();)? varзаставляет вас думать дважды, когда вы называете свои переменные, потому что это переключает внимание на функциональность, а не на тип (например UserCollection collection = new userRepository.GetUsers();, более естественным образом превращается в var users = userRepository.GetUsers();). Если вы думаете, что varнеясно, это просто потому, что не используется для этого.
Мартин Одхелиус
4
@MartinOdhelius varопределенно может сделать понятным код, используемый хорошо, но может также сделать его неясным слишком используемым; как много вариантов форматирования. Баланс зависит от того, насколько вы используете анонимные объекты и дженерики, ни один из которых не существовал в .NET 1.0, что делает его менее полезным в качестве гипотетического ключевого слова в первой версии C♯. Я бы назвал a только RadioButton radioButtonв случае фабричного или вспомогательного метода, где единственное, что значило в кнопке, было то, что она была RadioButton, иначе это безумие с или без var.
Джон Ханна
6
@Jon Hanna: Когда-то я был так же критичен, varкак и вы, если не больше, но я изменил свое мнение, и, возможно, это так же просто, как вопрос разных мнений, потому что я все еще думаю, что вы не правы, когда вы говорите, что это не имеет значения, сколько вы используете анонимных объектов и обобщений;) Объявление типа чаще всего является просто шумом кода, если вы не можете понять код без него, код, вероятно, неясен в любом случае.
Мартин Одхелиус,
3
Вы путаете var с анонимными типами . varсам по себе просто просит компилятор вывести тип из присваивания; это синтаксический сахар. Сначала я скептически относился к этому, но я использую это религиозно и еще не сталкивался со временем, когда это вызывало путаницу. Это устраняет избыточность при создании экземпляра и устраняет необходимость проверки типа при обращении к нему. В JAVA 9 нет эквивалента JAVA.
Robear
46

Если вы добавите Lombok в свой проект, вы можете использовать его ключевое слово val .

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

darthtrevino
источник
1
@rightfold: объекты, ссылка на finalкоторые не обязательно неизменна. Рассмотримfinal StringBuilder strB = new StringBuilder("My reference is final"); strB.append("I'm not immutable");
Матиас Браун
1
Начиная с lombok v1.16.12 также существует экспериментальная поддержка var. projectlombok.org/features/experimental/var.html
Рол Спилкер,
@MatthiasBraun ваш пример неверен. В этом случае сам класс StringBuilder является неизменным, вы просто добавляете строковое значение к его внутренней структуре, используя метод, это полностью допустимо.
Анджей Мациусович
27

JEP - Предложение по улучшению JDK

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

JEP 286: Вывод типа локальной переменной

Автор Брайан Гетц

// Goals:
var list = new ArrayList<String>();  // infers ArrayList<String>
var stream = list.stream();          // infers Stream<String>
blueberry0xff
источник
Какая версия Java? 10?
Питер Мортенсен
@PeterMortensen Да. JEP 286 был принят и опубликован в JDK 10 (см. 286 в разделе Возможности на openjdk.java.net/projects/jdk/10 ).
Джастин Альбано
20

Я подготовил плагин для IntelliJ, который - в некотором роде - дает вам varв Java. Это хак, поэтому применяются обычные заявления об отказе от ответственности, но если вы используете IntelliJ для разработки на Java и хотите попробовать его, он находится по адресу https://bitbucket.org/balpha/varsity .

balpha
источник
Было бы здорово иметь комбинацию клавиш для складывания / разворачивания типов объявлений в текущем редакторе. Отличный плагин, хотя.
горячая клавиша
2
@hotkey При этом используется встроенное свертывание кода IntelliJ, поэтому вы можете развернуть все с помощью Ctrl-Shift-NumPadPlus. Когда курсор находится на строке, содержащей объявление согнутой переменной, вы можете нажать Ctrl-NumPadPlus и Ctrl-NumPadMinus, чтобы сложить / развернуть объявления в текущем методе. Сложить все объявления немного неудобно, вы свернули все (Ctrl-Shift-NumPadMinus), а затем снова развернули все (Ctrl-Shift-NumPadPlus).
Балфа
18

С выпуском JDK 10 20 марта Java теперь включает varзарезервированное имя типа (не ключевое слово - см. Ниже), как указано в JEP 286 . Для локальных переменных в Java 10 или новее действует следующее:

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

varИмя зарезервированным типа в Java практически идентичен varключевому слову в C # в том , что оба позволяют неявного ввода (см ниже важных различий). varв Java может использоваться только для неявного вывода типов в следующих контекстах (как перечислено в JEP 286: Цели ):

  • локальные переменные с инициализаторами
  • индексы в расширенном цикле for
  • местные жители объявлены в традиционной петле

Поэтому var нельзя использовать для полей, возвращаемых типов, имен классов или имен интерфейсов. Его обоснование заключается в том, чтобы устранить необходимость включения длинных имен типов при объявлении и определении локальных переменных, как указано в JEP 286 (автор Брайан Гетц):

Мы стремимся улучшить опыт разработчиков, уменьшая церемонию, связанную с написанием кода Java, и в то же время поддерживая приверженность Java безопасности статических типов, позволяя разработчикам исключать часто ненужное объявление манифеста типов локальных переменных.

var Обзор в Java

Следует отметить, что varэто не ключевое слово в Java, а зарезервированное имя типа. Как указано в JEP 286:

Идентификатор var не является ключевым словом; вместо этого это зарезервированное имя типа. Это означает, что на код, который использует var как переменную, метод или имя пакета, это не повлияет; Это повлияет на код, использующий var в качестве имени класса или интерфейса (но на практике эти имена встречаются редко, поскольку они нарушают обычные соглашения об именах).

Обратите внимание, что поскольку varэто зарезервированное имя типа, а не ключевое слово, оно все равно может использоваться для имен пакетов, имен методов и имен переменных (вместе с его новой ролью вмешательства типа). Например, ниже приведены примеры правильного использования varJava:

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

Как указано в JEP 286:

Эта обработка будет ограничена локальными переменными с инициализаторами, индексами в расширенном цикле for и локальными переменными, объявленными в традиционном цикле for; он не будет доступен для формальных форм, конструкторов, типов возвращаемых методов, полей, формальных форм перехвата или любого другого типа объявления переменных.

Различия между varв Java & C

Это одно заметное различие между varC # и Java varзаключается в следующем: может использоваться как имя типа в C #, но не может использоваться как имя класса или имя интерфейса в Java. Согласно документации C # (неявно типизированные локальные переменные) :

Если названный тип varнаходится в области видимости, varключевое слово будет преобразовано в имя этого типа и не будет рассматриваться как часть неявно типизированного объявления локальной переменной.

Возможность использовать varв качестве имени типа в C # создает некоторую сложность и вводит некоторые сложные правила разрешения, которых varв Java избегают , запрещая varиспользовать имя класса или интерфейса. Для получения информации о сложностях varимен типов в C # см. Ограничения, применяемые к объявлениям переменных с неявным типом . Для получения дополнительной информации об обосновании решения о определении объема для `var в Java, см. JEP 286: Выбор области действия .

Джастин Альбано
источник
Есть ли разница между Java и c # в том, что вы не можете использовать varдля полей или возвращаемых типов? Почему важно отметить?
user1306322
@ user1306322 В этом контексте нет. varв Java нельзя использовать для полей или возвращаемых типов. Это важно, потому что это ограничение делает varконтекстно-зависимым, где оно может использоваться только в одних контекстах (локальные переменные), но не в других. Это не обязательно является разницей между Java и C #, что следует отметить, но является важным ограничением в целом при использовании varв Java.
Джастин Альбано,
Я только что посмотрел, и кажется, что в C # вы можете создать varимя класса и использовать его как таковой. Технически это «ключевое слово context» в случае c #, но в Java кажется, что вы не можете сделать то же самое. Поправьте меня если я ошибаюсь.
user1306322
1
Ты прав. Вы не можете использовать varв качестве имени класса или имени интерфейса в Java (что в любом случае не является распространенным), но вы можете использовать его для имен переменных, имен методов и имен пакетов. Например, var var = 1;является допустимым заявление Java , но при попытке объявить класс как public class var {}приводит к ошибке: as of release 10, 'var' is a restricted local variable type and cannot be used for type declarations. Я обновил ответ выше, чтобы более подробно рассказать об обосновании varJava и его различиях с varC #.
Джастин Альбано
11

Он будет поддерживаться в JDK 10. Его даже можно увидеть в действии в ранней сборке доступа .

СЭП 286 :

Расширение языка Java для расширения вывода типов для объявлений локальных переменных с инициализаторами.

Так что теперь вместо того, чтобы писать:

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

Ты пишешь:

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

Ноты:

  • varтеперь зарезервированное имя типа
  • Java по- прежнему привержена статической типизации!
  • Может использоваться только в объявлениях локальных переменных

Если вы хотите попробовать его без установки Java в вашей локальной системе, я создал образ Docker с установленным на нем JDK 10:

$ 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
Осторожно, код, который вы указали (до / после var), не эквивалентен. В varпримере listэто тип ArrayList, а не List.
Гили
8

Простое решение (при условии, что вы используете приличную IDE) - просто набрать int везде, а затем заставить его установить тип для вас.

На самом деле я просто добавил класс с именем 'var', поэтому мне не нужно вводить что-то другое.

Код все еще слишком многословен, но, по крайней мере, вам не нужно его печатать!

JonnyRaa
источник
Когда вы говорите "достойная IDE", Eclipse * исключается? - это не похоже на работу в Луне (по крайней мере, когда я только что попробовал это int) - я что-то упустил? (*: хотя я бы никогда не назвал Eclipse достойной IDE, я не могу судить за других ...)
BrainSlugs83
@ BrainSlugs83 Не знаю, я использую IDEA, ранее не использовал Eclipse. Разве это не исправляет типы для вас? Я привык к C # / Visual Studio / Resharper, который похож на IDEA за исключением того, что он на самом деле работает правильно! Во всех джетрейбинах вы можете нажать alt-enter, чтобы получить список предложений, когда есть ошибка - поэтому установка типа для int приводит к ошибке, которую вы можете вызвать при помощи alt-enter и заставить ее разбирать тип
JonnyRaa
5

Вы можете взглянуть на Kotlin JetBrains, но это val. не вар.

Артем
источник
4
Котлин имеет val и var. val эквивалентен объявлению переменной final в java, var позволяет переназначать.
samlewis
5

Java 10 действительно делала вывод типа локальной переменной, так что теперь она varв значительной степени эквивалентна C # one (насколько я знаю).

Он также может выводить не денодугируемые типы (типы, которые не могут быть названы в этом месте программистом; хотя, какие типы не денотируемые, отличается). См., Например, Трюки с varанонимными классами (которые вы никогда не должны использовать на работе) .

Единственное отличие, которое я смог найти, это то, что в C #

Если тип с именем var находится в области видимости, ключевое слово var будет преобразовано в имя этого типа и не будет рассматриваться как часть неявно типизированного объявления локальной переменной.

В Java 10 varнет допустимого имени типа.

Алексей романов
источник
@Lii Да, я не помню, что я имел в виду здесь, удалено.
Алексей Романов
Большой! Будут удалены мои комментарии, чтобы очистить историю!
Лий
4

По состоянию на Java 10, эквивалент ... var.

Брайан Гетц
источник
Существует ли какое - либо различие? Я имею в виду, что вы знаете лучше, чем писать короткие ответы, как это, что с вашим уровнем репутации n все. И, конечно же, должны быть некоторые различия.
user1306322
@ user1306322 Это совершенно отдельный вопрос! Вы можете проверить тег java-10, так как многие аспекты этого уже были заданы.
Брайан Гетц
Ну, это вопрос посмотреть, если вы это прибегая к помощи, так как речь идет о первом и связана в каждой соответствующей должности на боковой панели. Поэтому, я полагаю, если вы знаете этот отдельный вопрос, который отвечает на него, вы можете хотя бы дать ссылку на него или включить его часть в свой ответ.
user1306322
3

Я знаю, что это старше, но почему бы не создать класс var и создать конструкторы с различными типами, и в зависимости от того, какие конструкторы вызываются, вы получаете var с другим типом. Вы даже можете встроить методы для преобразования одного типа в другой.

Себастьян Заба
источник
3

Lombokподдерживает var, но все еще классифицируется как экспериментальный:

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

Вот ловушка, чтобы избежать, пытаясь использовать это в IntelliJ IDEA. Похоже, работает как ожидалось, включая автозаполнение и все. Пока не будет «нехакерского» решения (например, из-за JEP 286: Вывод типа локальной переменной ), это может быть вашим лучшим выбором прямо сейчас.

Обратите внимание, что valподдерживается Lombokтакже без изменения или создания lombok.config.

BullyWiiPlaza
источник
2

Вы можете, в Java 10, но только для локальных переменных, то есть

Ты можешь,

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

Но не могу,

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

Проверьте спецификации для получения дополнительной информации.

Анто кристен
источник
2
Это неверно varможет использоваться для многих форм неотмечаемых типов, включая типы захвата, типы пересечений и анонимные типы классов. И, начиная с Java 11, его также можно применять к лямбда-параметрам.
Брайан Гетц
0

В общем, вы можете использовать класс Object для любого типа, но вы должны выполнить приведение типов позже!

например:-

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);
Адитья Кумар
источник
Адитья, пожалуйста, проверьте все остальные ваши ответы. Многие из них имеют -1 и, вероятно, по уважительной причине. Не публикуйте что-либо, если вы не уверены, что это правильно.
user1306322
@ user1306322 в чем проблема в моем ответе! можешь уточнить? мы не можем использовать класс Object для всех типов данных?
Адитья Кумар
Объект объект = 12; Объект object1 = "Адитья"; Объект object2 = 12.12; System.out.println (Integer.parseInt (object.toString ()) + 2); System.out.println (object1.toString () + "Кумар"); System.out.println (Double.parseDouble (object2.toString ()) + 2.12);
Адитья Кумар
Проблема в том, что вы не поняли вопрос. Вопрос был не в том, «как заставить это работать», а в том, «есть ли такая вещь». Вы отвечаете не на тот вопрос. Теперь, когда varслово официально на языке, ваш ответ также относится к старомодному способу.
user1306322