Почему следующий код дает мне ошибку?
int n = 30000; // Some number
for (int i = 0;
0 <= n ? (i < n) : (i > n);
0 <= n ? (i++) : (i--)) { // ## Error "not a statement" ##
f(i,n);
}
Почему следующий код дает мне ошибку?
int n = 30000; // Some number
for (int i = 0;
0 <= n ? (i < n) : (i > n);
0 <= n ? (i++) : (i--)) { // ## Error "not a statement" ##
f(i,n);
}
Это потому, что цикл for
был определен таким образом в Спецификации языка Java.
14.14.1 Базовый для утверждения
BasicForStatement:
for ( ForInit ; Expression ; ForUpdate ) Statement
ForStatementNoShortIf:
for ( ForInit ; Expression ; ForUpdate ) StatementNoShortIf
ForInit:
StatementExpressionList
LocalVariableDeclaration
ForUpdate:
StatementExpressionList
StatementExpressionList:
StatementExpression
StatementExpressionList , StatementExpression
Таким образом, это должно быть StatementExpression
или несколько StatementExpression
s, а StatementExpression
определяется как:
StatementExpression:
Assignment
PreIncrementExpression
PreDecrementExpression
PostIncrementExpression
PostDecrementExpression
MethodInvocation
ClassInstanceCreationExpression
0 <= n ? (i++) : (i--)
ни один из них, поэтому он не принят. i += ((0 <= n) ? 1 : -1)
- это назначение, поэтому оно работает.
Прежде всего, я бы рекомендовал не писать код таким образом. Цель кода - "подсчитывать от нуля до n, если n положительно, отсчитывать от 0 до n, если n отрицательно", но я был бы склонен вместо этого писать:
for (int i = 0; i < abs(n); i += 1)
{
int argument = n < 0 ? -i : i;
f(argument, n);
}
Но это не отвечает на ваш вопрос, а именно:
Почему я не могу использовать операторы
?:
в третьем аргументе для циклов for в Java?
A for
цикл имеет структуру for ( initialization ; condition ; action )
.
Цель выражения - вычислить значение.
Цель инструкции - принять действие.
Есть несколько выражений, которые по дизайну вычисляют значение и принимают действие. i++
, i += j
, new foo()
, method()
и так далее.
Плохой стиль имеет любое другое выражение, которое вычисляет значение и принимает какое-либо действие. Такие выражения трудно понять.
Поэтому действие цикла for
ограничено только теми выражениями, которые по дизайну вычисляют значение и принимают действие.
В принципе, запрещая этот код, компилятор говорит вам, что вы сделали плохой стилистический выбор. b?i++:i--
является юридическим выражением, но это действительно плохой стиль, потому что он делает то, что предполагается вычислять в результате создания побочного эффекта и игнорирования значения.
заменить
0 <= n ? (i++) : (i--)
с
i += ((0 <= n) ? 1 : -1)
который должен работать
Ваш код дает вам ошибку в основном потому, что вы пытаетесь решить свою проблему с помощью недействительного алгоритма. Тот факт, что JLS не допускает тройной как условие в для цикла, тоже не помогает - но главная проблема заключается в том, что вы пропускаете действительное решение поставленной задачи.
Начнем с общего утверждения prematureOptimization == sqrt(sum(evil))
- сначала вы должны подумать о том, что вы хотите сделать, а не о том, как это сделать или почему код не работает.
i шаг должен быть 1, если n равно >= 0, в противном случае -1
(боковое примечание: если n инвариантно (и оно здесь), используя, например, abs (n) или n < 0 в условии, является плохой практикой, хотя большинство компиляторов попытается исключить инвариант из цикла, вы обычно должны просто использовать временный var для хранения результата и использовать результат вместо сравнения)
Итак, код под рукой должен быть:
void doSomething( int n ) {
if ( n >= 0 )
for( int i = 0; i < n; i++ )
f( i, n );
else
for( int i = 0; i > n; i-- )
f( i, n );
}
Факторизация инвариантов и разделение отдельных ветвей кода - это основные методы, используемые для повышения эффективности алгоритмов (а не преждевременная оптимизация, помните меня); там нет более быстрого и более чистого способа сделать это. Некоторые могут утверждать, что это случай loop unwinding - это очень хорошо, если бы не тот факт, что эти две петли не должны быть раны вместе в первую очередь...
Другое дело: третий цикл op в для всегда был обычным выражением; попробуйте угадать, почему не компилируется следующий код?
0 <= n ? (i++) : (i--); // error: not a statement
... может быть, потому что следующий код не будет компилироваться?
0 <= n ? i : i; // error: not a statement
... и что по той же причине приведенный ниже код не будет работать в Java?
i; // error: not a statement
Ваш ответ таков: ternary не является выражением - trernary просто возвращает значение, а значение не является выражением (по крайней мере, на Java); i++
и i--
разрешены в тройном порядке только потому, что они возвращают значение, но здесь также возникают побочные эффекты.