Чому Java не вводить умовивід?


44

Мені завжди було цікаво, чому Java не робить умовивід, враховуючи, що мова є такою, якою вона є, і її VM дуже зрілий. Google's Go - це приклад мови з чудовим виведенням тексту, і це зменшує кількість набраних тексту. Чи є якась особлива причина того, що ця функція не є частиною Java?


3
правила сумісності назад в мові, старої та популярної, як java
ratchet freak

9
@ratchetfreak Не вдалося ввести умовивід у відповідність назад? Старіші програми просто надавали б більше інформації, ніж потрібно.

1
При використанні з видаленням типу Erasure це може мати небажані ефекти. docs.oracle.com/javase/tutorial/java/generics/…
Zachary Yates

4
Зауважте, що Java 8 принесе багато варіантів вибору за допомогою своєї функції Lambda: ви можете писати складні лямбдати, не згадуючи жодних типів і всього, що робиться на основі висновку.
Йоахім Зауер

4
Локальний тип змінної виводиться на Java: JEP 286: Локальний варіант змінних
Джиммі Сторінка

Відповіді:


60

Технічно кажучи, у Java є типовий інтерес при використанні дженериків. З загальним методом, як

public <T> T foo(T t) {
  return t;
}

Компілятор проаналізує і зрозуміє це, коли ви пишете

// String
foo("bar");
// Integer
foo(new Integer(42));

Строку буде повернуто для першого виклику, а цілий - для другого виклику, виходячи з того, що було введено як аргумент. Ви отримаєте належну перевірку часу компіляції. Крім того, в Java 7 можна отримати деякий додатковий тип посилення при інстанціюванні таких дженериків

Map<String, String> foo = new HashMap<>();

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

Люди отримують вигоду від надмірності декларації типу двома способами. По-перше, резервний тип слугує цінною документацією - читачам не потрібно шукати декларацію getMap (), щоб дізнатися, який тип вона повертає. По-друге, надмірність дозволяє програмісту оголосити призначений тип і тим самим скористатися перехресною перевіркою, виконаною компілятором.

Доповідач, який закрив це, також зазначив, що він просто відчуває себе "не-java-подібним", з чим я один з цим погоджуватися. Багатослівність Яви може бути і благом, і прокляттям, але це робить мову такою, якою вона є.

Звичайно, що саме RFE не було кінцем цієї розмови. Під час Java 7 ця функція знову була розглянута , і були створені деякі тестові реалізації, зокрема один Джеймс Гослінг. Знову ж таки, ця функція була зрештою знята.

З випуском Java 8 тепер ми отримуємо висновок про тип як частину лямбдів як таких:

List<String> names = Arrays.asList("Tom", "Dick", "Harry");
Collections.sort(names, (first, second) -> first.compareTo(second));

Компілятор Java здатний розглянути метод, Collections#sort(List<T>, Comparator<? super T>)а потім інтерфейс Comparator#compare(T o1, T o2)та визначити, що firstі secondповинно бути, Stringтаким чином, дозволяючи програмісту відмовитися від необхідності перезавантажувати тип у виразі лямбда.


5
First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns- так, якщо це HashMap<String, Integer> map = foo.getMap()тоді я згоден - в C # я зазвичай не використовую varв таких випадках, хоча б міг. Але цей аргумент не тримає води, якщо він є HashMap<String, Integer> map = new HashMap<String, Integer>(). Це справжнє надмірність, і я не бачу ніякої користі в тому, щоб писати ім'я типу двічі. І як я виграв би тут перехресну перевірку компілятора, я взагалі не розумію.
Конрад Моравський

9
Так, це добре для дженериків, але я все одно пропускаю еквівалент C # varна Java.
Конрад Моравський

15
Що стосується того, що він є "не схожим на java", ця (сирна) історія приходить в голову;) 9gag.com/gag/2308699/-this-is-how-things-are-done-around-here
Конрад Моравський

6
Крім того, тип повернення функції часто є очевидним або непотрібним, і навіть у випадках, коли це не ваш IDE, можна позначити тип за півсекунди.
Фоши

8
Я вважаю, що офіційна цитата Humans benefit from the redundancyє справжньою відповіддю на поточне запитання, тому що кожне прочитане вами обгрунтування здається виправданим, необгрунтованим та смішним виправданням від дизайнерів Java: І C #, і C ++ мають особливість, дизайнери C # і C ++ не менш компетентні, ніж Java, і всі із задоволенням користуються ним. Що може призвести до того, що розробники Java відрізняються від розробників C # або C ++? Ось чому я погоджуюся з @KonradMorawski: "Ось так все робиться тут", здається, знову є справжньою закулісною причиною цього.
paercebal

16

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

Зауважимо, що це дозволено для дженериків, а причина, чому це не дозволено для негенеричних типів, здається, пов’язана з філософією - ніщо не заважає дизайнерам додати це.

Оновлення: схоже, що java 10 підтримує це - - http://openjdk.java.net/jeps/286


5

Наскільки мені відомо, коли Java розроблялася на початку дев'яностих років, висновок не був настільки популярний серед основних мов (але це вже була дуже відома концепція, наприклад, в ML). Отже, я можу уявити, що висновок типу, ймовірно, не підтримувався, тому що Java була спрямована на програмістів, що надходять із C ++, Pascal або інших основних мов, які цього не мали (принцип найменшого здивування).

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

Я не знаю, чи Java отримає висновок про тип у майбутньому, але ІМО, це було б великою революцією для мови (як згадував Гленн Нельсон, вона була описана як "не схожа на java"), і тоді можна також розглянути можливість відкидання назва Java на користь нового імені.

Якщо ви хочете використовувати мову JVM з висновком типу, ви можете використовувати Scala.


2

Я можу придумати кілька можливих причин. Одне полягає в тому, що явне введення тексту - це самодокументування. Як правило, Java робить це пріоритетним перед стислістю. Інша причина може бути у випадках, коли тип дещо неоднозначний. Наприклад, коли тип або будь-який підтип може задовольнити звичайну програму. Скажімо, ви хочете використовувати Список, але хтось приходить разом і використовує метод, ексклюзивний для ArrayList. JIT може зробити висновок про ArrayList і продовжувати, навіть якщо ви хочете помилку компіляції.


8
Як GridBagLayout сітчастий мішок = новий GridBagLayout (); додати до самостійної документації? Його чисте повторення.
Anders Lindén

3
Це розмежовується з випадком, коли два типи не є однаковими. Ви можете так само легко призначити екземпляр підкласу.
джиггі

Let's say you want to use a List, but someone comes along and uses a method exclusive to ArrayList. The JIT would infer an ArrayList and carry on even if you wanted a compilation error- Я цього не розумію. Виведення типу відбувається в момент встановлення змінної, а не виклику методу на ній. Не могли б ви показати приклад того, що ви мали на увазі?
Конрад Моравський

2
@KonradMorawski: Я припускаю, що він означає, що якщо метод повертає ArrayList, тип буде зроблений для цього. Якщо ви хочете трактувати тип як щось інше, ніж тип повернення, ви не можете використовувати умовиводи. Я не розумію, як це може колись бути проблемою в кодовій базі десь поблизу здорового.
Фоши

JIT не відіграватиме жодної ролі у висновках типу. Тип умовиводу - явище часу компіляції. і якщо змінна оголошена як посилання на Список, намагаючись отримати доступ до членів ArrayList на ній не буде вводити перевірку, і ви отримаєте помилку компіляції
sara

0

Це суперечить усталеній рекомендації оголошувати змінні за допомогою найбільш загального інтерфейсу, який відповідає вашим потребам, та ініціалізувати їх відповідним класом реалізації, як у

Collection<String> names = new ArrayList<>();

Ефективно,

var names = new ArrayList<String>();

не що інше, як синтаксичний цукор для

ArrayList<String> names = new ArrayList<String>();

Якщо ви цього хочете, ваш IDE може створити його з new ArrayList<String>()виразу "одним клацанням" (рефактор / створення локальної змінної), але пам’ятайте, що це суперечить рекомендації "використовувати інтерфейси".

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