Подтвердить что ты не робот

Почему я не могу использовать?: Операторы в третьем аргументе for for loop в Java?

Почему следующий код дает мне ошибку?

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);
}
4b9b3361

Ответ 1

Это потому, что цикл 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 определяется как:

14.8. Выражения выражений

StatementExpression:
    Assignment
    PreIncrementExpression
    PreDecrementExpression
    PostIncrementExpression
    PostDecrementExpression
    MethodInvocation
    ClassInstanceCreationExpression

0 <= n ? (i++) : (i--) ни один из них, поэтому он не принят. i += ((0 <= n) ? 1 : -1) - это назначение, поэтому оно работает.

Ответ 2

Прежде всего, я бы рекомендовал не писать код таким образом. Цель кода - "подсчитывать от нуля до 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-- является юридическим выражением, но это действительно плохой стиль, потому что он делает то, что предполагается вычислять в результате создания побочного эффекта и игнорирования значения.

Ответ 3

заменить

0 <= n ? (i++) : (i--)

с

i += ((0 <= n) ? 1 : -1)

который должен работать

Ответ 4

Ваш код дает вам ошибку в основном потому, что вы пытаетесь решить свою проблему с помощью недействительного алгоритма. Тот факт, что JLS не допускает тройной как условие в для цикла, тоже не помогает - но главная проблема заключается в том, что вы пропускаете действительное решение поставленной задачи.

Начнем с общего утверждения prematureOptimization == sqrt(sum(evil)) - сначала вы должны подумать о том, что вы хотите сделать, а не о том, как это сделать или почему код не работает.

  • цикл должен просто выполняться n раз, используя я в качестве счетчика
  • 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-- разрешены в тройном порядке только потому, что они возвращают значение, но здесь также возникают побочные эффекты.