Почему Java запрещает инициализатор массива в качестве аргумента вызова метода?

В Java мы можем определить переменную массива и инициализировать ее следующим образом:

int[] prime10 = new int[] { 2, 3, 5, 7 };

В JLS правая часть присваивания называется ArrayCreationExpression. Инициализатор в терминах синтаксиса JLS: ArrayInitializer .

Как и все выражения, ArrayCreationExpression можно использовать в списке аргументов вызова метода:

callMe(new int[] { 2, 3, 5, 7 });

Однако мы также можем использовать более короткую форму VariableInitializer, только с ArrayInitializer:

int[] prime10 = { 2, 3, 5, 7 };

но мы не можем использовать тот же инициализатор в вызов метода

// ILLEGAL IN JAVA
callMe({ 2, 3, 5, 7 });

Конечно, понятно, почему не получается компиляция, при анализе синтаксиса — выдержка из JLS:

VariableDeclarator:
  VariableDeclaratorId [= VariableInitializer]

VariableInitializer:
  Expression 
  ArrayInitializer

MethodInvocation:
  MethodName ( [ArgumentList] )
  // plus other variants...

ArgumentList:
  Expression {, Expression}

но почему было принято такое решение? Почему бы не сделать ArrayInitializer Expression или хотя бы добавить вариант с ArrayInitializer к ArgumentList? Является ли это чисто синтаксическим или есть другие причины (возможно, вывод типа), которые запрещают такое расширение?

ОБНОВЛЕНИЕ

После некоторых замечаний в духе "откуда вы знаете тип {1, 2, 3}", техническое уточнение.

При вызове метода формальные параметры метода определяют допустимые типы аргументов. Итак, если у меня есть объявление метода:

void callMe(Number[] numbers) {
  //...
}

затем вопросительный звонок

callMe({ 1, 2, 3 }); // still ILLEGAL in Java

означало бы

callMe(new Number[] { 1, 2, 3 });

Так что здесь нет проблем. Мой вопрос не к самоуверенным "кому это нужно" - кому в любом случае нужны лямбда-выражения, бриллианты и var ;) - а скорее, что запрещает (формально) такую ​​конструкцию с точки зрения JLS или, по крайней мере, с точки зрения " Java-архитекторы», вводящие такие функции в язык?


person pwes    schedule 08.02.2019    source источник


Ответы (2)


Каким будет тип массива {2, 3, 5, 7} ?

байт[] ??? короткая[] ??? символ [] ??? длинный[] ???

Если это указано явно, это прямо здесь. Если это выводится с использованием какого-либо правила, принятого для него, это еще одно правило, которое нужно изучить разработчику.

(PS в инициализаторах переменных это можно вывести из объявления типа переменной. В вызовах методов это нельзя вывести из сигнатуры метода, потому что привязка метода работает с точностью до наоборот: сначала должны быть известны типы аргументов, потому что они определяющий фактор в определении того, какой метод рассматривается.)

person Erwin Smout    schedule 08.02.2019
comment
это еще одно правило, которое нужно усвоить разработчику. Этот аргумент довольно слаб, если подумать о дополнительных правилах вывода, которые были добавлены в Java, такие как оператор алмаза или val, начиная с Java 10. Таким образом, новые правила не являются проблемой для сопровождающих Java. . - person Tom; 08.02.2019
comment
В наши дни java уже не так сильно увлекается, но я думаю, что многие люди уже укусили обратную сторону комфорта val. - person Erwin Smout; 08.02.2019
comment
Были ли у людей проблемы с новым правилом или нет, сейчас это не имеет значения, важно то, решил ли архитектор Java не реализовывать новую функцию, потому что это означало новые правила. Добавление других вещей (таких как алмазный оператор или val) показывает, что новые правила, похоже, не имеют большого значения. Так что это само по себе не будет причиной того, что он еще не реализован. - person Tom; 08.02.2019

Понятно, почему было принято такое решение. Какой набор правил вы бы предложили для определения типа {1, 2, 3} или {1, "dasqwe", "c"} и т. д.? Создает больше проблем, чем решает.

person Sanya Ovcharova    schedule 08.02.2019
comment
Вам не нужны никакие специальные правила, они уже есть, называются контекст вызова; при вызове метода именно формальные параметры объявления метода сообщают компилятору, какие типы следует ожидать. Таким образом, тип компонента массива будет определяться объявлением метода. Что касается {1, "dasqwe", 'c' }, это не проблема, если вы знаете тип компонента (как было предложено выше, из формальных параметров), например. Number[] b = { 1, 1.2, new BigDecimal("1.20000000001") работает отлично. - person pwes; 09.02.2019