29 votes

Pourquoi ne puis-je l'utiliser ?: les opérateurs dans le 3ème argument de boucles for en Java?

Pourquoi le code suivant me donne une erreur?

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

47voto

eis Points 14687

C'est parce que l' for boucle a été défini ainsi dans le Langage Java Spécification.

14.14.1 La base d'une déclaration

BasicForStatement:
    for ( ForInit ; Expression ; ForUpdate ) Statement

ForStatementNoShortIf:
    for ( ForInit ; Expression ; ForUpdate ) StatementNoShortIf

ForInit:
    StatementExpressionList
    LocalVariableDeclaration

ForUpdate:
    StatementExpressionList


StatementExpressionList:
    StatementExpression
    StatementExpressionList , StatementExpression

Il se doit donc d'être un StatementExpression ou multiple, StatementExpressions et StatementExpression est défini comme:

14.8 Expression des déclarations

StatementExpression:
    Assignment
    PreIncrementExpression
    PreDecrementExpression
    PostIncrementExpression
    PostDecrementExpression
    MethodInvocation
    ClassInstanceCreationExpression

0 <= n ? (i++) : (i--) est aucun de ceux-ci, de sorte qu'il n'est pas acceptée. i += ((0 <= n) ? 1 : -1) est une affectation, de sorte qu'il fonctionne.

23voto

Eric Lippert Points 300275

Tout d'abord, je vous recommande d'écrire le code de cette façon. Le but du code est de "compter à partir de zéro à n si n est positif, le compte à rebours de 0 à n, si n est négatif", mais j'ai tendance à plutôt écrire:

for (int i = 0; i < abs(n); i += 1)
{
    int argument = n < 0 ? -i : i;
    f(argument, n);
}

Mais cela ne veut pas répondre à votre question, qui est:

Pourquoi ne puis-je pas utiliser ?: opérateurs dans le 3ème argument de boucles for en Java?

Un for boucle a la structure en for ( initialization ; condition ; action ).

Le but d'une expression est de calculer une valeur.

Le but de l' instruction est de prendre une action.

Il y a certaines expressions qui de par leur design à la fois de calculer une valeur et prendre des mesures. i++, i += j, new foo(), method() et ainsi de suite.

Il est mauvais style à toute autre expression qui calcule à la fois une valeur et prend une action. De telles expressions sont difficiles à comprendre.

Par conséquent, l'action de l' for boucle est limité à seulement ceux expressions qui de par leur design à la fois de calculer une valeur et prendre des mesures.

Fondamentalement, en interdisant à ce code, le compilateur est vous dire que vous avez fait un mauvais choix stylistiques. b?i++:i-- est une expression juridique, mais il est vraiment mauvais style, parce qu'il rend ce qui est censé être le calcul d'une valeur en produisant un effet secondaire et en ignorant la valeur.

17voto

eitanfar Points 2491

remplacer

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

avec

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

cela devrait fonctionner

4voto

vaxquis Points 2122

Votre code vous donne une erreur surtout parce que vous essayez de résoudre votre problème avec des non valide algorithme. Le fait que JLS ne permet pas ternaire comme condition dans la boucle for n'aide pas non plus - mais le principal problème est que vous manquez de la validité de la solution de la tâche à portée de main.

Commençons par une déclaration commune, "l'optimisation prématurée == sqrt(sum(mal))" - d'abord, vous devez considérer ce que vous voulez faire, pas comment le faire, ou pourquoi le code ne fonctionne pas.

  • la boucle doit exécuter n fois, j'ai comme un compteur
  • je l'étape devrait être de 1 si n >= 0, sinon -1

    (note: si n est invariante (et c'est ici) en utilisant par exemple abs(n) ou n < 0 dans l'état est une mauvaise pratique; bien que la plupart compilateur va essayer de facteur de l'invariant de la boucle, vous devez simplement utiliser un temporaire var pour stocker le résultat et utiliser le résultat de la comparaison à la place)

Donc, le code devrait être:

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

L'affacturage des invariants et la séparation distincte de branches de code sont les techniques de base utilisées pour augmenter l'efficacité des algorithmes de (pas une optimisation prématurée, l'esprit me); il n'y a pas plus rapide ni plus propre façon de le faire. Certains prétendent que c'est un cas de boucle de déroulement - il très bien serait, si ce n'est pour le fait que ces deux boucles ne devrait pas être enroulés ensemble en premier lieu...

Une autre chose: le tiers de l'op dans de boucle a toujours été un régulier de la déclaration; nous allons essayer de deviner pourquoi ne pas le code suivant compile?

0 <= n ? (i++) : (i--); // error: not a statement

... peut-être parce que code suivant ne compile pas non plus?

0 <= n ? i : i; // error: not a statement

... et c'est pour la même raison, le code ci-dessous ne fonctionne pas en Java soit?

i; // error: not a statement

Votre réponse est: ternaire n'est pas un énoncé - ternaire renvoie simplement la valeur, et la valeur n'est pas une déclaration (au moins en Java); ++i et i - sont autorisés dans ternaire juste parce qu'ils renvoient une valeur, mais ils produisent également des effets secondaires ici.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X