Який еквівалент ключового слова C # 'var' на Java?


264

Одне використання ключового слова var у C # - це неявне оголошення типу. Що таке еквівалентний синтаксис Java для var ?


4
val(або var) якщо ви використовуєте певну мову "Заміна Java" ;-)

6
@pst: це була б Скала? Гм так, так і є.
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 років тому це було неможливо на Яві (усі типи мали назви, навіть якщо вони були надзвичайно багатослівними та непривабливими). Я не знаю, чи змінилося це середнім часом.

  • varне те саме, що dynamic. variables досі на 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
@Mike Caron: C # має [не за замовчуванням] невіртуальні дзвінки, а оператори не віртуальні, так що ... var p = new X(); p.Z()це не те саме, що SuperX p = new X(); p.Z()для всіх X і SuperX, хоча X : SuperX. З varв статичному типі з pзавжди Xв першому прикладі вище, але завжди SuperXв другому прикладі. Тонка, але важлива різниця, яку слід пам’ятати. Але ваша відповідь дуже правильна :-)

200
@Jon Hanna: varне робить код менш зрозумілим. На мою думку, навпаки. Чому, наприклад, напишіть тип два (або навіть три) рази на одному рядку, коли ви декларуєте та інстанціюєте це ( RadioButton radioButton = new RadioButton();)? varзмушує вас думати двічі, коли ви називаєте свої змінні, тому що це перетворює фокус на функціональність, а не на тип (наприклад UserCollection collection = new userRepository.GetUsers();, більш природно перетворюється на var users = userRepository.GetUsers();). Якщо ви думаєте, що varце незрозуміло, це просто тому, що він не використовується.
Мартін Оделій

4
@MartinOdhelius varнапевно може зробити код зрозумілим, що використовується добре, але він також може зробити його незрозумілим занадто погано використовуваним; як і багато варіантів форматування. Баланс відрізняється залежно від того, скільки ви використовуєте анонімні об'єкти та дженерики, жоден з яких не існував у .NET 1.0, що робить його менш корисним як гіпотетичне ключове слово у першій версії C♯. Я б назвав лише RadioButton radioButtonте, що стосується фабричного або допоміжного методу, де єдине, що важливе для кнопки, - це те, що це було RadioButton, інакше це безумство з чи без var.
Джон Ханна

6
@Jon Hanna: Я колись був настільки ж критичним, varяк і ви, якщо не більше, але я змінив свою думку, і, можливо, це так просто, як питання різних думок, тому що я все ще думаю, що ви помиляєтесь, коли кажете, що це скільки б ви не використовували анонімні об'єкти та дженерики;) Декларація типу - це найчастіше просто шум коду, якщо ви не можете зрозуміти код, без нього код, ймовірно, не зрозумілий в будь-якому випадку.
Мартін Оделій

3
Ви плутаєте var з анонімними типами . varсам просто просить компілятор вивести тип із призначення; це синтаксичний цукор. Спочатку я скептично ставився до цього, але релігійно використовую його і ще не стикаюся з часом, коли це викликало плутанину. Це знімає надмірність при інстанціюванні та усуває необхідність перевірки типу при посиланні. Немає жодного еквівалента JAVA станом на JAVA 9.
Robear

46

Якщо ви додасте Lombok до свого проекту, ви можете використовувати його ключове слово val .

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


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
Рул Spilker

@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>

Яка версія Java? 10?
Пітер Мортенсен

@PeterMortensen Так. JEP 286 був прийнятий і опублікований у JDK 10 (див. 286 у розділі Особливості на openjdk.java.net/projects/jdk/10 ).
Джастін Альбано

20

Я підготував плагін для IntelliJ, який - певним чином - дає вам varJava. Це злом, тому застосовуються звичайні відмови від відповідальності, але якщо ви використовуєте IntelliJ для своєї розробки Java і хочете спробувати це, це за адресою https://bitbucket.org/balpha/varsity .


Було б чудово мати ярлик на клавіатурі для складання / розгортання типів декларацій у поточному редакторі. Хоча чудовий плагін.
гаряча клавіша

2
@hotkey Для цього використовується вбудований код IntelliJ, тому ви можете розгортати все за допомогою Ctrl-Shift-NumPadPlus. Коли курсор знаходиться у рядку, що містить складене оголошення змінної, ви можете Ctrl-NumPadPlus і Ctrl-NumPadMinus скласти / розгорнути декларації в поточному методі. Складати всі декларації трохи незручно, ви склали все (Ctrl-Shift-NumPadMinus) і потім знову все розгортаєте (Ctrl-Shift-NumPadPlus).
balpha

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 (автор Brian Goetz):

Ми прагнемо покращити досвід розробника, зменшивши церемонію, пов’язану з написанням коду Java, зберігаючи прихильність Java до безпеки статичного типу, дозволяючи розробникам ухилятися від часто непотрібного декларації локальних змінних.

var Оцінка роботи на Java

Слід зазначити, що varце не ключове слово на Java, а скоріше зарезервоване ім’я типу. Як цитується з JEP 286:

Ідентифікатор var - це не ключове слово; натомість це ім’я зарезервованого типу. Це означає, що код, який використовує var як змінну, метод або ім'я пакета, не впливатиме; Код, який використовує var як ім'я класу або інтерфейсу, буде зачеплений (але ці імена на практиці рідкісні, оскільки вони порушують звичайні умови іменування).

Зауважте, що оскільки varце зарезервоване ім’я типу, а не ключове слово, воно все одно може використовуватися для імен пакетів, назв методів та назв змінних (разом із новою роллю інтерференції типу). Наприклад, наступні приклади дійсних застосувань varна Java:

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

Як цитується з JEP 286:

Ця обробка буде обмежена локальними змінними з ініціалізаторами, індексами в розширеному for-loop та локальними локальними мережами, оголошеними в традиційному for-loop; він не буде доступний для формалів методів, формалів конструктора, типів повернення методу, полів, формалів спіймання або будь-якого іншого виду змінної декларації.

Відмінності між varJava та 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ім'я класу та використовувати його як таке. Технічно це "контекстне ключове слово" у випадку c #, але на Java схоже, що ви не можете зробити те ж саме. Виправте мене, якщо я помиляюся.
користувач1306322

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 та її відмінності varв C #.
Джастін Альбано

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, а не a List.
Гілі

8

Просте рішення (якщо припустити, що ви використовуєте гідний IDE) - просто ввести "int" скрізь, а потім отримати його, щоб встановити тип для вас.

Я фактично лише додав клас під назвою "var", тому мені не потрібно вводити щось інше.

Код все ще занадто багатослівний, але принаймні вам не потрібно його вводити!


Коли ви говорите "пристойний IDE", Eclipse * виключається? - це, здається, не працює у Luna (принаймні, коли я просто спробував це int) - я щось пропускаю? (*: поки я ніколи не називатиму Eclipse гідним IDE, я не можу судити про інших ...)
BrainSlugs83

@ BrainSlugs83 не використовую IDEA, але не використовував затемнення раніше. Це не виправляє типи для вас? Я звик до c # / visual studio / resharper, який схожий на IDEA, за винятком того, що він працює належним чином! У всіх "jetbrains" ви можете натиснути alt-enter, щоб отримати список пропозицій, коли є помилка - тому тип налаштування int вводить помилку, яку ви можете ввести і ввести її для сортування типу
JonnyRaa

5

Ви можете подивитися на Kotlin від JetBrains, але це val. не вар.


4
У Котліна є вал і вар. val еквівалентно оголошенню змінної фіналу в java, var дозволяє перепризначити.
samlewis

5

Java 10 отримав локальний висновок змінної типу, тому тепер він varє майже еквівалентним C # one (наскільки я знаю).

Крім того , можна зробити висновок , НЕ denotable типів (типи , які не можуть бути названі в тому місці , програміст, хоча , які типу не є denotable різне). Див. Наприклад, Прийоми з varта анонімними заняттями (які ви ніколи не використовуєте на роботі) .

Єдина відмінність, яку я міг би знайти, - це те, що в C #,

Якщо тип з назвою var знаходиться в області дії, то ключове слово var буде дозволено до цього імені типу і не розглядатиметься як частина неявно введеної декларації локальної змінної.

У Java 10 varне є юридичним іменем типу.


@Lii Так, я не пам'ятаю, що я тут мав на увазі, видалено.
Олексій Романов

Чудово! Видалить мій коментар для очищення історії!
Лій

4

Станом на Java 10, еквівалент ... var.


Чи існує якесь - або відмінність? Я маю на увазі, що ти краще знаєш, ніж писати короткі відповіді, як це, що з твоїм рівнем повторень. І неодмінно мають бути деякі відмінності.
користувач1306322

@ user1306322 Це зовсім окреме питання! Ви можете перевірити тег java-10, оскільки багато аспектів цього вже було задано.
Брайан Гец

Ну, це питання подивитися, якщо ви це вдаючись до допомоги, тому що мова йде про першому і пов'язана в кожній відповідній посаді на бічній панелі. Тож я гадаю, що якщо ви знаєте це окреме запитання, яке відповідає на нього, ви могли б принаймні покластись на нього або включити до нього відповіді.
користувач1306322

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.


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; Object object1 = "Aditya"; Об'єкт об'єкта2 = 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.